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 f
has a single fixed type Foo<'a, &'b i32>
and by the variance rules for mutable references, &'b i32
is invariant and thus 'b
is invariant.
However, f
is used with T
as two separate lifetimes via p2
and p4
. How does the compiler choose? Well it cannot shorten the lifetime used by p2
into that of p4
, because then p2
can be modified to reference something of a smaller lifetime and thus p2
can dangle at the last println!
(consider what would happen if you added *f.a = &p3;
right after assigning f.a
to &mut p2
). The only option is for the lifetime used by p4
to be widened to match p2
.
Since p4
must match the lifetime of p2
, the assignment from p3
is now too short, so you get the error you see.
The second example works because the lifetime used by p2
does not extend after the println!
in the inner block, so p3
can satisfy that lifetime.