l can't understand the borrowing system in rust. Can anyone help me understand this
My code:
let mut current_val:&mut Value = &mut *logs;
for key in &group_path {
let mut temp: Option<&mut serde_json::Value> = None; // Explicit type might help clarity.
// Check if the key exists and if not, insert a new object.
if !current_val.as_object_mut().unwrap().contains_key(key) {
current_val.as_object_mut().unwrap().insert(key.clone(),
serde_json::Value::Object(Default::default()));
}
temp = current_val.get_mut(key);
// Update `current_val` for the next iteration
if let Some(t) = temp {
current_val = t;
} else {
break; // or continue, depending on your logic
}
}
if let Some(arr) = current_val.as_array_mut() {
arr.push(serde_json::to_value(log).unwrap());
} else {
println!("Not array");
}
error:
error[E0499]: cannot borrow `*current_val` as mutable more than once at a time
--> src/logger.rs:92:28
|
82 | temp = current_val.get_mut(key);
| ----------- first mutable borrow occurs here
...
92 | if let Some(arr) = current_val.as_array_mut() {
| ^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
In theory, temp should have been removed and there should have been no problem with borrowing
I've just started learning rust, and there are so many problems. it seems like a simple task. What do you recommend to read to better understand how to do it?
Is there any way to do this without using "polonius-the-crab"?
It's not related to Polonius. This kind of code will likely never be accepted.
Your code can be simplified, removing irrelevant code and changing a loop into a single iteration:
let mut current_val: &mut Value = &mut *logs;
let key = &group_path[0];
if let Some(t) = current_val.get_mut(key) {
current_val = t;
}
if let Some(arr) = current_val.as_array_mut() {
arr.push(serde_json::to_value(log).unwrap());
} else {
println!("Not array");
}
Hopefully the issue is clear now. Depending on whether the key exists in the map, current_val can be set either to a = &mut * logs or b = &mut (&mut *logs)[key]. The latter is a borrow of the former. In the current_val.as_array_mut() expression, you borrow mutably the variable which can be either of those values, thus both borrows a and b must exist simultaneously. But this means that logs is borrowed mutably twice, which is what the borrow checker complains about. actually it complains about a slightly different but essentially the same issue: instead of double-borrowing logs, it fails on the double-borrow of current_val itself, but the reason is the same --- it may be reborrowed in the branch, and both direct borrow and double borrow are thus possible in current_val.as_array_mut() call.
struct Thing;
impl Thing {
fn maybe_next(&mut self) -> Option<&mut Self> {
Some(self)
}
}
let mut temp = &mut Thing;
if let Some(x) = temp.maybe_next() {
temp = x;
}
if let Some(x) = temp.maybe_next() {
temp = x;
}
I try to describe here the the problem in simple words: The borrow checker currently behaves here as it does, because at if let Some(x) = temp.maybe_next() a borrow with the lifetime 'a (=same lifetime as temp) is created but it doesn't consider to release the borrow for everything that happens afterwards because it could also be the case that the inner assignment won't happen if the outer condition is wrong. Is that about right?