fn main() {
let string1 = String::from("abcd");
let string2 = "xyz";
let result = longest(string1.as_str(),string2);
println!("The longest string is {}",result);
}
fn longest<'a>(x:&'a str,y:&'a str) -> &'a str{
if x.len() > y.len(){
x
}else{
y
}
}
In the above example, is the lifetime of 'a equal to the lifetime of 'string2'?Are lifetime and scopes the same?
the string slice returned from the function will live at least as long as lifetime 'a,so,the lifetime of 'result' is also equal to 'a,but 'result' has a smaller scope than 'string2',Doesn't that contradict the fact that they both have a lifetime of 'a
No. Lifetimes can begin and end at different points than scopes begin and end; and in fact they aren't even required to be contiguous.
No. The string referenced by string2 lives for the 'static lifetime. Obviously, the function can't accept or return a reference with the 'static lifetime, because it accepts and potentially returns the reference to a local variable, string1.
It's covariance. A reference to a long-living object can be converted to a reference with a shorter lifetime. Again, in the above case, the compiler chooses 'a to be the shorter of the two lifetimes, hence, the lifetime of string1.
how to understand this sentence:“Lifetimes can begin and end at different points than scopes begin and end; and in fact they aren't even required to be contiguous.”
Lifetimes and scopes are related. For example the lifetime of a refetence to some data is limited by the scope of its owner. A lifetime is generally not limited by the scope of the reference. And also commonly a borrow's lifetime is a lot shorter than the scope of the owner.
Let's illustrate these points:
let r: &str;
{
let owner = String::from("hi");
r = &owner;
// r can be alive here
println!("{r}");
}
// you may not use `r` here anymore
// because the scope of `owner` has ended
// this would fail:
// println!("{r}");
let r: &str;
let owner = String::from("hi");
{
let scoped_r = &owner;
// scoped_r can be used here
println!("{scoped_r}");
// let's assign r to scoped_r
r = scoped_r;
// a re-borrow would even work as well
// same behavior:
// r = &*scoped_r;
}
// you can use `r` here
// because the scope of `owner` has not ended yet
println!("{r}");
// the scope of scoped_r is irrelevant - it was able
// to have a lifetime bigger than its own scope
I don't think an example of lifetimes being short is required. Short-lived references are super common.
I'm not entirely sure what exact phenomenon @H2CO3 had in mind for non-contiguous lifetimes.
The lifetime of the reference returned may not exceed that of 'a. (explicit)
Where does 'a come from might be good question. longest is a generic function; So the compiler chooses; At the point it is called; variant(*) copies of two argument references are taken.
The second is just a copy of string2: &'static str
The construction of the first reference happens at the . [dot] operator and makes a temporary variable. Call its type &'dot String. Then goes through as_str(), variance comes into play making another temporary; call its type &'elide str. 'elide may not exceed 'dot.
End choice the compiler makes is 'a may not exceed the union of 'elide and 'static.
The construction of the reference is where that magic 'dot happened. It is the start of the compiler tracking how long the borrowing lasts. So ensures the lifetime of result may not exceed the lifetime of string1.