(Hi all, I'm still learning Rust and its borrow checking and this may be a beginner's question.)
Why doesn't the following code compile?
struct Node<'a> {
value: i32,
next: Option<&'a Node<'a>>,
}
fn bar<'a>(list: &'a mut Node<'a>) {
list.value += 2;
}
fn foo<'a>(list: &'a mut Node<'a>) {
for _i in 0..10 {
bar(list);
}
list.value += 1;
}
fn main() {
let mut list = Node {
value: 0,
next: None,
};
foo(&mut list);
println!("{}", list.value);
}
Here are the error messages:
Compiling playground v0.0.1 (/playground)
error[E0499]: cannot borrow `*list` as mutable more than once at a time
--> src/main.rs:12:13
|
10 | fn foo<'a>(list: &'a mut Node<'a>) {
| -- lifetime `'a` defined here
11 | for _i in 0..10 {
12 | bar(list);
| ----^^^^-
| | |
| | `*list` was mutably borrowed here in the previous iteration of the loop
| argument requires that `*list` is borrowed for `'a`
error[E0503]: cannot use `list.value` because it was mutably borrowed
--> src/main.rs:14:5
|
10 | fn foo<'a>(list: &'a mut Node<'a>) {
| -- lifetime `'a` defined here
11 | for _i in 0..10 {
12 | bar(list);
| ---------
| | |
| | `*list` is borrowed here
| argument requires that `*list` is borrowed for `'a`
13 | }
14 | list.value += 1;
| ^^^^^^^^^^^^^^^ use of borrowed `*list`
error[E0502]: cannot borrow `list.value` as immutable because it is also borrowed as mutable
--> src/main.rs:23:20
|
22 | foo(&mut list);
| --------- mutable borrow occurs here
23 | println!("{}", list.value);
| ^^^^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
Some errors have detailed explanations: E0499, E0502, E0503.
For more information about an error, try `rustc --explain E0499`.
error: could not compile `playground` due to 3 previous errors
Here's what I thought about these errors:
E0499: It says, "A variable was borrowed as mutable more than once", but in foo
it seems to me like we are simply passing the already borrowed mutable reference list
as a call argument, as opposed to borrowing it again.
E0503: It says, "A value was used after it was mutably borrowed", but likewise it looks like we are simply operating on the already-borrowed mutable reference list
, as opposed to using it directly or via another reference.
E0502: It says, "A variable already borrowed as immutable was borrowed as mutable", but it seems to me that the lifetime of the mutable reference &mut list
ends at the foo call (line 22) and it's safe to access list.value
after it (line 23).
Now how do people reason about this, and how would you fix the code?
if I manually, fully inline foo
and bar
into main
, it compiles. Does passing a mutable reference as a call argument count as mutably borrowing it again? And doing it in a loop is considered as mutably borrowing multiple times?
If I change the type of list
from &'a mut Node<'a>
to &'a mut Node<'b>
in foo
and bar
, it compiles, which I don't know why.
Thank you!