fn main() {
struct Foo<'a, T> {
a: &'a mut T,
}
let p1 = 1;
let mut p2 = &p1;
{
let p3 = 2;
let mut p4 = &p3;
let mut f = Foo {
a: &mut p4,
};
f.a = &mut p2;
println!("{}", f.a);
}
println!("{}", p2);
}
While run this program, it meets error such as:
error[E0597]: `p3` does not live long enough
--> src/main.rs:10:19
|
10 | let mut p4 = &p3;
| ^^^ borrowed value does not live long enough
...
16 | }
| - `p3` dropped here while still borrowed
17 | println!("{}", p2);
| -- borrow later used here
-- borrow later used here
this is my first question: why exist these errors?
If I annotate the last line, such as :
fn main() {
struct Foo<'a, T> {
a: &'a mut T,
}
let p1 = 1;
let mut p2 = &p1;
{
let p3 = 2;
let mut p4 = &p3;
let mut f = Foo {
a: &mut p4,
};
f.a = &mut p2;
println!("{}", f.a);
}
// println!("{}", p2);
}
It runs successfully. By refer to rustonomicon,
f.a = &mut p2;
&'a mut T is covariant over 'a and invariant over T, It should compile unsuccesfully. But successfully, why?
If I annotate the last line, It should compile unsuccesfully.
The core of the problem is that
fhas a single fixed typeFoo<'a, &'b i32>and by the variance rules for mutable references,&'b i32is invariant and thus'bis invariant.However,
fis used withTas two separate lifetimes viap2andp4. How does the compiler choose? Well it cannot shorten the lifetime used byp2into that ofp4, because thenp2can be modified to reference something of a smaller lifetime and thusp2can dangle at the lastprintln!(consider what would happen if you added*f.a = &p3;right after assigningf.ato&mut p2). The only option is for the lifetime used byp4to be widened to matchp2.Since
p4must match the lifetime ofp2, the assignment fromp3is now too short, so you get the error you see.The second example works because the lifetime used by
p2does not extend after theprintln!in the inner block, sop3can satisfy that lifetime.