Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot borrow `x` as mutable more than once at a time

Tags:

rust

In the following code (playground):

struct Node {     datum: &'static str,     edges: Vec<Node>, }  fn add<'a>(node: &'a mut Node, data: &'static str) -> &'a Node {     node.edges.push(Node {         datum: data,         edges: Vec::new(),     });     &node.edges[node.edges.len() - 1] // return just added one }  fn traverse<F>(root: &Node, callback: &F) where     F: Fn(&'static str), {     callback(root.datum);     for node in &root.edges {         traverse(node, callback);     } }  fn main() {     let mut tree = Node {         datum: "start",         edges: Vec::new(),     };      let lvl1 = add(&mut tree, "level1");      traverse(&mut tree, &|x| println!("{:}", x)); //I actually don't need mutability here } 

I have this error:

error[E0499]: cannot borrow `tree` as mutable more than once at a time   --> src/main.rs:32:19    | 30 |     let lvl1 = add(&mut tree, "level1");    |                         ---- first mutable borrow occurs here 31 |  32 |     traverse(&mut tree, &|x| println!("{:}", x)); //I actually don't need mutability here    |                   ^^^^ second mutable borrow occurs here 33 | }    | - first borrow ends here 

My question seems to be very similar to Why does Rust want to borrow a variable as mutable more than once at a time?, but I'm not sure. If so, is there a workaround for this case?

like image 891
tower120 Avatar asked Jul 07 '15 23:07

tower120


1 Answers

This happens because of how add is defined:

fn add<'a>(node: &'a mut Node, data: &'static str) -> &'a Node 

Here it is specified that the lifetime of the resulting reference should be equal to the lifetime of the incoming reference. The only way it is possible (except for unsafe code) is that the resulting reference is somehow derived from the incoming reference, for example, it references some field inside the object the incoming reference points at:

struct X {     a: u32,     b: u32, }  fn borrow_a<'a>(x: &'a mut X) -> &'a mut u32 {     &mut x.a } 

However, there is no way for the compiler to know what exactly from the incoming structure is borrowed by looking only at the function signature (which, in general, is the only thing it can do when compiling code which uses this function). Therefore, it can't know that the following code is technically correct:

let mut x = X { a: 1, b: 2 }; let a = borrow_a(&mut x); let b = &mut x.b; 

We know that a and b are disjoint because they point at different parts of the structure, but the compiler can't know that because there is nothing in borrow_a's signature which would suggest it (and there can't be, Rust does not support it).

Therefore, the only sensible thing the compiler could do is to consider the whole x to be borrowed until the reference returned by borrow_a() is dropped. Otherwise it would be possible to create two mutable references for the same data, which is a violation of Rust aliasing guarantees.

Note that the following code is correct:

let mut x = X { a: 1, b: 2 }; let a = &mut x.a; let b = &mut x.b; 

Here the compiler can see that a and b never point to the same data, even though they do point inside of the same structure.

There is no workaround for this, and the only solution would be to restructure the code so it doesn't have such borrowing patterns.

like image 70
Vladimir Matveev Avatar answered Oct 02 '22 17:10

Vladimir Matveev