Generic lifetime annotations ('a), compiler elision rules, and subtyping relationships (Covariance vs Invariance).
// Lifetime 'a states: output reference is valid for as long as BOTH x and y are valid.
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
fn main() {
let string1 = String::from("long string is long");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
println!("Longest: {}", result);
}
// println!("{}", result); // Error: string2 dropped! (E0597)
}Every reference in Rust has an associated lifetime representing the span of code where the referenced data is guaranteed valid.
When a function returns a reference derived from its input arguments, the compiler requires explicit lifetime annotations (e.g. `'a`) if it cannot disambiguate which input parameter the output borrows from.
Variance describes how subtyping of lifetimes applies to composite types. Because `'static` outlives `'a`, `'static` is a subtype of `'a` (`'static: 'a`).
Immutable references `&'a T` are covariant over `'a` and `T`. Mutable references `&'a mut T` are covariant over `'a` but invariant over `T`.
1. Each elided lifetime in parameters becomes a distinct lifetime. 2. If there is exactly one input lifetime parameter, that lifetime is assigned to all elided output lifetimes. 3. If there are multiple input parameters and one is `&self` or `&mut self`, the lifetime of `self` is assigned to all output lifetimes.
fn get_str(&self) -> &str
// Desugars into:
fn get_str<'a>(&'a self) -> &'a strCreating a reference that outlives the memory stack frame of the value it points to.
Returning a pointer or reference to data allocated on the current stack frame, which is deallocated when the function returns.