Reputation: 61
In the definition of lifetime_things
, the lifetime of 'b
is longer than 'a
, but actually when I call this function, x1
is longer than y1
, but this can compile successfully:
//here you could see 'b:'a means, the lifetime of b should be larger than a,
fn lifetime_things<'a,'b:'a>(x:&'a String, y:&'b String) ->&'a String {
if x.len() > y.len() {
&x
} else {
&y
}
}
fn main() {
let z: i32;
let x = String::from("1");
let x1=&x;
{
let y = String::from("2");
let y1=&y;
println!("{}",lifetime_things(x1,y1));
}
}
But here you could see the lifetime of x1
should be larger than y1
so why can this compile successfully as well?
Upvotes: 4
Views: 268
Reputation: 2507
'b: 'a
means 'b
must outlive 'a
, which in turn means whenever 'a
is live, so must 'b
. Crucially, this is a larger than or equals relationship. Also notice that lifetimes don't work like types. When a function takes an 'v
reference, any lifetime ('w
) will be accepted as long as 'w: 'v
.
So, where is 'a
live? In the body of the function and whenever the returned string reference is used after the call. We can visualize it like this:
fn lifetime_things<'a,'b:'a>(x:&'a String, y:&'b String) ->&'a String {
if x.len() > y.len() { // <-+
&x // |
} else { // |
&y // +----+
} // | |
} // <-+ |
// |
fn main() { // +-- 'a
let z: i32; // |
let x = String::from("1"); // |
let x1=&x; // |
{ // |
let y = String::from("2"); // |
let y1=&y; // |
println!("{}",lifetime_things(x1,y1)); // <------+
}
}
Notice, that since the value returned by lifetime_things
is only printed, 'a
is only live on the line println!("{}",lifetime_things(x1,y1));
(exclusing lifetime_things
s body).
So, to call lifetime_things
we simply need the both arguments to at least be live at the call. This holds for both x1
and y1
, so it all checks out.
Upvotes: 4