Reputation: 1486
In Rust if a structure is like this
struct Node {
next: Option<Box<Node>>,
}
Then to implement a method to find the tail and add a new node on it might look like this
fn add1<'a>(mut node: &'a mut Node) {
while let Some(next) = node.next.as_deref_mut() {
node = next;
}
node.next = Some(Box::new(Node { next: None }));
}
Then error like this encountered:
error[E0506]: cannot assign to `node.next` because it is borrowed
--> src/lib.rs:16:5
|
12 | fn add1<'a>(mut node: &'a mut Node) {
| -- lifetime `'a` defined here
13 | while let Some(next) = node.next.as_deref_mut() {
| ------------------------
| |
| borrow of `node.next` occurs here
| argument requires that `node.next` is borrowed for `'a`
...
16 | node.next = Some(Box::new(Node { next: None }));
| ^^^^^^^^^ assignment to borrowed `node.next` occurs here
Some other variation also cannot work:
fn add1_borken_ergonomics(mut node: &mut Node) {
while let Some(next) = &mut node.next {
node = next;
}
node.next = Some(Box::new(Node { next: None }));
}
fn add1_borken_explicit<'a>(mut node: &'a mut Node) {
while let Some(ref mut next) = *&mut node.next {
node = next;
}
node.next = Some(Box::new(Node { next: None }));
}
which gives similar error like
error[E0506]: cannot assign to `node.next` because it is borrowed
--> src/lib.rs:30:5
|
26 | fn add1_borken_explicit(mut node: &mut Node) {
| - let's call the lifetime of this reference `'1`
27 | while let Some(ref mut next) = *&mut node.next {
| ------------ -------------- borrow of `node.next` occurs here
| |
| assignment requires that `node.next` is borrowed for `'1`
...
30 | node.next = Some(Box::new(Node { next: None }));
| ^^^^^^^^^ assignment to borrowed `node.next` occurs here
So the questions is, why writing like this blow it will then work
fn add1_working<'a>(mut node: &'a mut Node) {
while let Some(ref mut next) = node.next {
node = next;
}
node.next = Some(Box::new(Node { next: None }));
}
The code above should all mean the same but compilers treat them differently?
Rust playground for the example code above. And the same issue can be seen with another simpler code example as well (from the issue page, see below.)
After asked around I found an issue related to this https://github.com/rust-lang/rust/issues/67957, but it seems not mentioning whether it is some compiler bug that can be fixed later, or it is because we need some better understanding in some aspects of the language?
Upvotes: 4
Views: 556
Reputation: 1664
This is a known bug.
I got the explanation from the rust forum:
There's another bug report related to this, similar to the one linked in that StackOverflow thread but with a bit more discussion: if/while Some(n) = &mut foo sugar will leak a temporary mutable borrow to current scope in particular situation · Issue #62013 · rust-lang/rust · GitHub
I didn't follow all of the details, but I believe the difference in behavior here is unintentional and will be fixed eventually. When compiling with the next-generation borrow checker Polonius, both functions compile successfully.
Upvotes: 2