I have two questions about lifetime parameters and concrete lifetimes.
Q1:
Consider this uncompilable code: (from a question on StackOverflow)
mod case2 {
#[derive(Debug)]
struct Foo {}
#[derive(Debug)]
struct Bar2<'b> {
x: &'b Foo,
}
impl<'b> Bar2<'b> {
fn f(&'b mut self) -> &'b Foo {
self.x
}
}
fn f4() {
let foo = Foo {};
let mut bar2 = Bar2 { x: &foo }; // #1
bar2.f(); // #2 'bar2' is borrowed as mutable
let z = bar2.f(); // #3 error: cannot borrow `bar2` as mutable more than once at a time [E0499]
}
}
After reading the not-so-clear accepted answer, here is my understanding of the problem. Firstly, annotation x: &'a T
means 'a
is the lifetime of the reference x
itself, not the referent (according to this post). In function f4
, 'b
is bound to the lifetime of the variable bar2
when creating bar2
at line #1, so according to the definition fn f(&'b mut self) -> &'b Foo
, the lifetime of reference self
created at line #2 is the same as the lifetime of variable bar2
, so comes the error at line #3.
However if I change the code of f4
to this:
fn f4() {
let foo = Foo {}; // #1
let mut bar2 = Bar2 { x: &foo }; // #2
println!("{:?}", &bar2); // #3
bar2.f(); // #4
}
This compiles fine, which indicates that the lifetime of reference self
created at line #4 is not exactly the lifetime of bar2
. Instead, it is shortened somehow. Otherwise, line #3 will cause an error.
My question is: what is exactly the concrete lifetime for 'b, and the lifetime of reference self
created at line #4? And what are the rules the compiler follows to determine these?
Q2:
This question is about lifetime variance. This code compiles fine:
#[derive(Debug)]
struct Foo<'a> {
x: &'a i32,
}
impl<'a> Foo<'a> {
fn set(&mut self, r: &'a i32) {
self.x = r;
}
}
fn main() {
let v = 5; // #1
let mut w = 7; // #2
let mut f = Foo { x: &v }; // #3
println!("f is {:?}", f); // #4
{
let r = &mut w; // #5
*r += 1; // #6
}
f.set(&w); // #7
println!("now f is {:?}", f); // #8
}
I am wondering what is the concrete lifetime for the parameter 'a
of f
in function main
? And what is the concrete lifetime for reference &w
at line #7?
The problem here is, the concrete lifetime (say 'a0
) for 'a
of Foo
needs to span from line #3 to line #8 to ensure the reference in Foo
is valid. However, the lifetime of reference &w
at line #7 doesn't contain line #5 and line #6 (otherwise, it will cause a compilation error). So the lifetime of &w
(say 'b
) is strictly contained by 'a0
. Now we consider variance: 'b
is a supertype of 'a0
, which means arguments expecting one &'a0 T
reference cannot accept a reference with lifetime 'b
, so line #7 will cause a compilation error, which doesn't happen.