Lifetimes
Subtyping and Lifetime Relationships
Although Rust does not have class inheritance, it has lifetime subtyping: if lifetime 'long completely contains lifetime 'short ('long: 'short), then 'long is a subtype of 'short ('long <: 'short).
Why a Longer Lifetime Is a Subtype of a Shorter Lifetime
In type theory, Sub <: Super means a value of type Sub can be safely substituted wherever a value of type Super is expected.
- If code expects a reference valid for a short region
'short, passing a reference valid for a longer region'long(or'static) is always safe. - Conversely, if code requires a reference valid for
'long, passing a reference that expires early ('short) is unsound and rejected.
Region inclusion:
'static ⊇ 'long ⊇ 'short
Subtyping relationship (substitutability):
'static <: 'long <: 'short
&'static T can be used where &'long T is expected,
and &'long T can be used where &'short T is expected.
Lifetime Coercion in Practice
Because &'long T is a subtype of &'short T, the compiler automatically shrinks the lifetime of shared references to find a common lifetime when combining two references from different scopes:
fn pick_first<'a>(x: &'a str, _y: &'a str) -> &'a str {
x
}
fn main() {
let static_str: &'static str = "I live for 'static";
{
let local_string = String::from("I live for the inner block");
let local_ref: &str = &local_string; // lifetime `'short`
// `static_str` (`&'static str`) is a subtype of `&'short str`,
// so both arguments coerce to `&'short str`!
let result = pick_first(static_str, local_ref);
println!("Picked: {result}");
}
}
Picked: I live for 'static
Subtyping Cannot Extend a Shorter Lifetime
Subtyping is one-way ('long <: 'short). Attempting to assign a reference with a shorter lifetime into a variable that requires a longer lifetime fails to compile:
// ❌ does not compile
fn main() {
let outer = String::from("outer");
let mut r: &str = &outer; // `r` lives for the outer scope
{
let inner = String::from("inner");
r = &inner; // Error: `&'short str` cannot be used where `&'long str` is required
println!("{r}");
}
println!("{r}");
}
error[E0597]: `inner` does not live long enough
--> src/main.rs:8:13
|
7 | let inner = String::from("inner");
| ----- binding `inner` declared here
8 | r = &inner; // Error: `&'short str` cannot be used where `&'long str` is required
| ^^^^^^ borrowed value does not live long enough
9 | println!("{r}");
10 | }
| - `inner` dropped here while still borrowed
11 |
12 | println!("{r}");
| - borrow later used here