What is going on here (playground)?
struct Number { num: i32 } impl Number { fn set(&mut self, new_num: i32) { self.num = new_num; } fn get(&self) -> i32 { self.num } } fn main() { let mut n = Number{ num: 0 }; n.set(n.get() + 1); }
Gives this error:
error[E0502]: cannot borrow `n` as immutable because it is also borrowed as mutable --> <anon>:17:11 | 17 | n.set(n.get() + 1); | - ^ - mutable borrow ends here | | | | | immutable borrow occurs here | mutable borrow occurs here
However if you simply change the code to this it works:
fn main() { let mut n = Number{ num: 0 }; let tmp = n.get() + 1; n.set(tmp); }
To me those look exactly equivalent - I mean, I would expect the former to be transformed to the latter during compilation. Doesn't Rust evaluate all function parameters before evaluating the next-level-up function call?
This line:
n.set(n.get() + 1);
is desugared into
Number::set(&mut n, n.get() + 1);
The error message might be a bit more clear now:
error[E0502]: cannot borrow `n` as immutable because it is also borrowed as mutable --> <anon>:18:25 | 18 | Number::set(&mut n, n.get() + 1); | - ^ - mutable borrow ends here | | | | | immutable borrow occurs here | mutable borrow occurs here
As Rust evaluates arguments left to right, that code is equivalent to this:
let arg1 = &mut n; let arg2 = n.get() + 1; Number::set(arg1, arg2);
Editor's note: This code example gives an intuitive sense of the underlying problem, but isn't completely accurate. The expanded code still fails even with non-lexical lifetimes, but the original code compiles. For the full description of the problem, review the comments in the original implementation of the borrow checker
It should now be obvious what is wrong. Swapping those first two lines fixes this, but Rust does not do that kind of control-flow analysis.
This was first created as bug #6268, now it is integrated into RFC 2094, non-lexical-lifetimes. If you use Rust 1.36 or newer, NLL is enabled automatically and your code will now compile without an error.
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With