---
title: Lifetime
url: https://doc.liz6.com/en/rust/01-ownership-and-borrowing/03-lifetime
locale: en
area: rust
tags:
- rust
- ownership-and-borrowing
date: null
modified: 2026-07-16
description: Lifetime Lifetimes ('a) are not runtime values—they are compile-time constraints on the valid scope of references. From elision rules (automatically inferred by…
---

# Lifetime

> Lifetimes (`'a`) are not runtime values—they are compile-time constraints on the valid scope of references. From elision rules (automatically inferred by the compiler) to explicit annotations (structs, variance, HRTBs), lifetime annotations essentially tell the borrow checker "which of these references outlives the others."

## Lifetime is a Compile-Time Concept

Lifetime parameters (`'a`) are not runtime values—they are compile-time **constraints**: the valid scope of this reference cannot be longer than `'a`. The compiler uses region inference in MIR to deduce the minimal lifetime.

## Lifetime Elision

Most functions do not require explicit lifetime annotations—the compiler automatically infers them based on 3 rules:

1. Each reference parameter without a lifetime annotation is assigned an independent lifetime (`fn foo<'a, 'b>(x: &'a T, y: &'b U)`)
2. If there is only one input lifetime, it is assigned to all output lifetimes (`fn foo<'a>(x: &'a T) -> &'a U`)
3. If there are multiple input lifetimes and one of them is `&self` or `&mut self`, the `self` lifetime is assigned to all outputs

Rule 2 is the most common: a single reference parameter → the returned reference defaults to borrowing that parameter. Rule 3 is why method chaining works: the borrow of `self` is passed to the return value.

## Lifetime in Structs

When a struct contains references, you must explicitly annotate the lifetime:

```rust
struct Excerpt<'a> {
    part: &'a str,                   // This reference cannot outlive 'a
}

impl<'a> Excerpt<'a> {
    fn announce(&self, msg: &str) -> &str {  // Rule 3: output borrows self
        println!("{}", msg);
        self.part
    }
}
```

The compiler's guarantee: an instance of `Excerpt<'a>` cannot outlive the referenced `&'a str`.

## 'static

`'static` is the only lifetime with a "special" meaning—it indicates that the referenced data lives for the entire duration of the program. Sources include:

- String literals: the type of `"hello"` is `&'static str`—embedded in the binary at compile time, always valid
- `Box::leak(Box::new(T))` can produce `&'static mut T`
- `static` variables and `const` references

## Variance

Rust lifetimes have **subtyping variance**. Key rules to understand:

- `'long: 'short` (meaning `'long` outlives `'short`, so `'long` satisfies the constraint of `'short`)
- `&'a T`: covariant in `'a` (if `'long: 'short`, then `&'long T` can be used where `&'short T` is expected)
- `&'a mut T`: invariant in `'a` (you cannot shorten the lifetime of a mutable reference—otherwise it might violate the aliasing XOR mutation rule)

```rust
fn assign<T>(to: &mut T, from: T) { *to = from; }

let mut x: &'static str = "hello";
{
    let y = String::from("world");
    // assign(&mut x, y.as_str());   // ERROR: T = &'static str (from to), but y is &'y str
}
// If this compiled, x would point to y's data → y gets dropped → dangling pointer
```

## HRTB (Higher-Ranked Trait Bounds)

When a closure parameter has a lifetime but does not need to be explicitly declared:

```rust
fn apply<F>(f: F) where F: for<'a> Fn(&'a str) -> &'a str { ... }
// "f satisfies Fn(&'a str) -> &'a str for **any** lifetime 'a"
// No need to specify 'a at the call site—the compiler automatically quantifies it
```

## PhantomData

When a struct has a lifetime but does not directly store a reference—use `PhantomData` to mark ownership/borrowing relationships:

```rust
use std::marker::PhantomData;

struct MyIter<'a, T> {
    ptr: *const T,                   // Raw pointer — does not carry Rust's borrowing relationship!
    _marker: PhantomData<&'a T>,     // Tells the compiler: "this struct logically holds &'a T"
}
```

## References

- **Rust Book**: Chapter 10.3 — Validating References with Lifetimes
- **Rust Reference**: lifetime elision, variance
- **RFC**: RFC 2094 (NLL), RFC 387 (Higher-Ranked Trait Bounds)

*Keywords: lifetime, elision, 'static, variance, covariant, invariant, HRTB, PhantomData, region inference*
