I'm learning lifetimes. The following example (made up by me) looks confusing. Can you help on the lifetime annotation here? What does 'a resolve to in the caller side?
// This code compiles, which is confusing to me.
fn f<'a>(r: &'a &'a i32) -> &'a i32 {
*r
}
fn main() {
let x: i32 = 5;
let y = &x;
let w: &i32; // Assigned in the inner scope.
{
// Lifetime 'a starts here?
let z = &y; // &'a &'a i32?
w = f(z);
// Lifetime 'a ends here?
}
// Compiles, why?
// Why w is still valid here? Isn't `'a` gone out of scope?
// How does the `'a` in `f` resolve?
println!("{:?}", w);
}
I think the more practical interpretation of "the 'a thing" is borrow context/set of loans (instead of "lifetime"). I'll be using '{set of borrows} (invented) syntax as a "resolved" lifetime parameter. So, if I write type &'{x} T that means references of this type borrow variable x immutably.
So on your case
let y = &x;
could be "expanded" to
let y: &'{x} i32 = &x;
Similarly,
let z = &y;
expands to
let z: &'{x, y} &'{x} i32 = &y;
// (note: borrow of `x` propagates, because `y` already borrowed `x`)
So, in the function call f(z), we can see that the lifetime parametersborrow contexts on the references are different, but since the function declares them as the same (&'a&'a i32), the both get converted to the superset – '{x, y}.
We can then desugar:
let w: &'{x, y} &'{x, y} i32;
// ...
w = f::<'{x, y}>(z);
Since the variable w borrows only from x and y, it's safe to use it after the {} block (you can see, there's not a trace of z in the borrow context) and thus the println compiles.
(Your example would stop compiling, if you also put y in the {} block, because the f's signature is actually quite restrictive – w actually only points to x, despite its type that says it borrows also y. If you modified the signature to fn<'a>(r: &&'a i32) -> 'a i32), it'd compile again).
Ah I see. Thanks for the quick and clear explanation! Your expansion clear shows that it's about the borrow of x and y, nothing to do with z actually (z's lifetime is irrelevant here). I think that's where I went wrong! Thanks for the clear explanation again!