Rust中while循环避免`*branch`多次可变借用的解决方案
解决serde_json树形结构转换中的可变借用编译错误
需求说明
输入JSON结构:
[{"key": "a", "children": [{"key": "a1", "children": [{"key": "a11", "children": []}]}]}, {"key": "b", "children": [{"key": "b1", "children": [{"key": "b11", "children": []}]}]}]
期望转换后的输出JSON:
{"a": {"a1": {"a11": ""}}, "b": {"b1": {"b11": ""}}}
初始实现代码
use serde_json::{json, Value}; use std::{collections::VecDeque}; fn convert_tree(lst: &Vec<serde_json::Value>) -> serde_json::Value { let mut tree = serde_json::Map::new(); let mut queue = VecDeque::new(); queue.push_back((lst, &mut tree)); while let Some((entries, branch)) = queue.pop_front() { for entry in entries { let key = entry["key"].as_str().unwrap(); let children = entry["children"].as_array(); if let Some(children) = children { let child_branch = serde_json::Map::new(); branch.insert(key.to_owned(), serde_json::Value::Object(child_branch)); let mut branch_ref = branch.get_mut(key).unwrap().as_object_mut().unwrap(); queue.push_back((children, &mut branch_ref)); } else { branch.insert(key.to_owned(), serde_json::Value::String("".to_owned())); } } } serde_json::Value::Object(tree) } #[test] fn test_convert_tree(){ let a_str = r#"[{"key": "a", "children": [{"key": "a1", "children": [{"key": "a11", "children": []}]}]}, {"key": "b", "children": [{"key": "b1", "children": [{"key": "b11", "children": []}]}]}]"#; let v: Vec<serde_json::Value>= serde_json::from_str(a_str).unwrap(); println!("{:#?}", v); let zed = convert_tree(&v); }
编译错误信息
执行测试命令 cargo test --package flashlight --example test_serde_json2 -- test_convert_tree --exact --nocapture 后出现以下错误:
error[E0499]: cannot borrow `*branch` as mutable more than once at a time --> examples/test_serde_json2.rs:68:17 | 68 | branch.insert(key.to_owned(), serde_json::Value::Object(child_branch)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here 69 | let mut branch_ref = branch.get_mut(key).unwrap().as_object_mut().unwrap(); | ------------------- first mutable borrow occurs here 70 | queue.push_back((children, &mut branch_ref)); | -------------------------------------------- first borrow later used here error[E0499]: cannot borrow `*branch` as mutable more than once at a time --> examples/test_serde_json2.rs:69:38 | 62 | while let Some((entries, branch)) = queue.pop_front() { | ----------------- first borrow used here, in later iteration of loop ... 69 | let mut branch_ref = branch.get_mut(key).unwrap().as_object_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^ `*branch` was mutably borrowed here in the previous iteration of the loop error[E0597]: `branch_ref` does not live long enough --> examples/test_serde_json2.rs:70:44 | 62 | while let Some((entries, branch)) = queue.pop_front() { | ----------------- borrow later used here ... 70 | queue.push_back((children, &mut branch_ref)); | ^^^^^^^^^^^^^^^ borrowed value does not live long enough 71 | } else { | - `branch_ref` dropped here while still borrowed error[E0499]: cannot borrow `*branch` as mutable more than once at a time --> examples/test_serde_json2.rs:72:17 | 62 | while let Some((entries, branch)) = queue.pop_front() { | ----------------- first borrow later used here ... 69 | let mut branch_ref = branch.get_mut(key).unwrap().as_object_mut().unwrap(); | ------------------- first mutable borrow occurs here ... 72 | branch.insert(key.to_owned(), serde_json::Value::String("".to_owned())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here Some errors have detailed explanations: E0499, E0597. For more information about an error, try `rustc --explain E0499`. warning: `flashlight` (example "test_serde_json2" test) generated 1 warning error: could not compile `flashlight` due to 4 previous errors; 1 warning emitted
问题分析与改进尝试
问题根源在于多次可变借用branch:插入新节点后又立即获取其可变引用,导致编译器判定违反借用规则。如果能一步完成插入并获取引用,就能解决问题——类似std::collections::HashMap的try_insert方法的效果。
尝试用entry方法合并插入与获取操作,改写后的代码如下:
use serde_json::{Map, Value}; use std::collections::VecDeque; fn insert_and_get<'a>(map: &'a mut Map<String, Value>, key: String, value: Value) -> &'a mut Value { map.entry(key).or_insert(value) } fn convert_tree(lst: &Vec<serde_json::Value>) -> serde_json::Value { let mut tree = serde_json::Map::new(); let mut queue = VecDeque::new(); queue.push_back((lst, &mut tree)); while let Some((entries, branch)) = queue.pop_front() { for entry in entries { let key = entry["key"].as_str().unwrap(); let children = entry["children"].as_array(); if let Some(children) = children { let child_branch = json!({}); let zed = insert_and_get(branch, key.to_owned(), child_branch).as_object_mut().unwrap(); queue.push_back((children, zed)); } else { branch.insert(key.to_owned(), serde_json::Value::String("".to_owned())); } } } serde_json::Value::Object(tree) }
内容的提问来源于stack exchange,提问作者ComplicatedPhenomenon
相关产品推荐
相关产品推荐

