Lifetimes

Multiple Lifetime Parameters

A function, struct, or method requires multiple lifetime parameters ('a, 'b, etc.) when it accepts or stores multiple references whose lifetimes must remain independent rather than being forced into a single shared lifetime.

Why a Single Lifetime Can Be Too Restrictive

When two input references share the same lifetime parameter 'a, the borrow checker intersects their lifetimes to the shorter of the two. If the return value only comes from the first parameter, tying the second parameter to 'a unnecessarily restricts how long the returned reference can live:

// `prefix` has its own lifetime `'b` because the returned slice
// only ever borrows from `text` (`'a`).
fn strip_prefix_or_full<'a, 'b>(text: &'a str, prefix: &'b str) -> &'a str {
    match text.strip_prefix(prefix) {
        Some(rest) => rest,
        None => text,
    }
}

fn main() {
    let long_lived_text = String::from("Bearer secret_token_123");
    let token: &str;

    {
        let short_lived_prefix = String::from("Bearer ");
        // Works because `short_lived_prefix` uses `'b`, while `token` gets `'a`!
        token = strip_prefix_or_full(&long_lived_text, &short_lived_prefix);
    } // `short_lived_prefix` is dropped here

    println!("Extracted token: {token}");
}
Extracted token: secret_token_123

If strip_prefix_or_full had been written with a single lifetime fn strip_prefix_or_full<'a>(text: &'a str, prefix: &'a str) -> &'a str, the code above would fail to compile because 'a would shrink to the inner block's scope of short_lived_prefix.

Timeline with single `'a` (REJECTED):
  long_lived_text:  |-----------------------------------|
  short_lived_prefix:     |------------|
  inferred `'a`:          |------------|  <-- `token` dies here!

Timeline with `'a` and `'b` (ACCEPTED):
  long_lived_text ('a):   |-----------------------------------|
  short_lived_prefix ('b):    |------------|
  `token: &'a str`:       |-----------------------------------|

Multiple Lifetimes in Structs

A struct that holds two references with independent lifetimes uses two lifetime parameters 'a and 'b when one reference may outlive the struct's use of the other:

struct ContextParser<'cfg, 'input> {
    config_delimiter: &'cfg str,
    current_input: &'input str,
}

impl<'cfg, 'input> ContextParser<'cfg, 'input> {
    // Returns a slice tied ONLY to `'input`, not `'cfg`:
    fn first_field(&self) -> &'input str {
        self.current_input
            .split(self.config_delimiter)
            .next()
            .unwrap_or("")
    }
}

fn main() {
    let input = String::from("alice:admin:1000");
    let username: &str;

    {
        let delimiter = String::from(":");
        let parser = ContextParser {
            config_delimiter: &delimiter,
            current_input: &input,
        };
        username = parser.first_field();
    } // `delimiter` and `parser` are dropped here, but `username` borrows `input` ('input)!

    println!("Parsed username: {username}");
}
Parsed username: alice

When to Use One vs. Multiple Lifetime Parameters

Scenario Annotation Reason
Output may come from either input x or y <'a>(x: &'a str, y: &'a str) -> &'a str Output cannot outlive whichever input is shorter
Output comes exclusively from x; y is only inspected <'a>(x: &'a str, y: &str) -> &'a str y gets an independent (elided) lifetime so it does not constrain the output
Struct stores two references that come from different scopes and one is extracted struct S<'a, 'b> { x: &'a T, y: &'b U } Keeps 'a and 'b decoupled when extracting &'a T