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