let mut i = 0i32;
let j = {
let r = &i; // immutable reference
let rr = &r;
&**rr
}
but the following failed
let mut i = 0i32;
let j = {
let r = &mut i; // mutable reference
let rr = &r;
&**rr
}
error[E0597]: `r` does not live long enough
--> demo.rs:21:18
|
19 | let j: &i32 = {
| - borrow later stored here
20 | let r = &mut i;
21 | let rr = &r;
| ^^ borrowed value does not live long enough
22 | &**rr
23 | };
| - `r` dropped here while still borrowed
I have read the do-references-to-mutable-references-need-to-be-mutable, but still could not understand why the mutability of the borrow inside the scope was reported as a lifetime error.
I read this medium, but not quite satisfied with the explanation. Why doesn't the immutable version trigger a lifetime error?
Right, this is an interesting point. The difference is that if you have a double reference and flatten it, the lifetimes don't end up in the same way:
&'short &'long T becomes &'long T when flattened.
&'short &'long mut T becomes &'short T when flattened.
So the problem in your case is that if j has the lifetime 'long, it's fine, but it is not fine if it has the 'short lifetime.
The reason for this is that if you could get a &'long T in the second case, then it would be possible for the flattened reference to exist while the mutable reference is usable, but mutable references must have exclusive access. To illustrate:
fn main() {
let mut i = 0i32;
let r = &mut i;
let j = {
let rr = &r;
&**rr
};
*r = 10;
// println!("{}", j);
}
If you change the above code to use the println, then the mutable reference was not exclusive when you used it, and therefore it will fail to compile. However if r was immutable, then the above would be fine because immutable references are allowed to be shared.
Hi, @alice, thanks to your explanation I understand it now. By the way, where does such knowledge come from ? I don't remember the book says about this (I read it a year ago).