All posts

Rust / Lifetime Elision Rules

Posted On 01.18.2022

Before Rust 1.0, writing code that returns a reference without any lifetime annotation wouldn’t compile. Because Rust does not know what’s the lifetime of the returned reference:

// 🚫 would not compile
fn first_word(s: &str) -> &str { ... }
 
// ✅ compile
fn first_word<'a>(s: &'a str) -> &'a str {

In later versions, the Rust compiler can automatically analyze and figure out the lifetime. It is called lifetime elision and is based on a set of rules. For now, these rules are applied for the fn and impl blocks. In the future, more elision rules will be added.

In a function, lifetimes on the parameters are called input lifetimes, and lifetimes on the return values are called output lifetimes.

If the lifetimes are not explicitly annotated, the compiler will try to apply these three rules:

  • Each parameter that is a reference gets its own lifetime parameter, for example:

    fn foo(first: &str)
    // is equivalent to
    fn foo<'a>(first: &'a str)
     
    fn foo(first: &str, second: &Bar)
    // is equivalent to
    fn foo<'a, 'b>(first: &'a str, second: &'b Bar)
    
  • If there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters:

    fn foo(first: &str) -> &str
    // is equivalent to
    fn foo<'a>(first: &'a str) -> &'a str
    
  • If there are multiple input lifetime parameters, but one of them is &self or &mut self, the lifetime of self will be assigned to all output lifetime parameters:

    fn foo(&self, first: &str) -> &str 
    // is equivalent to
    fn foo<'a, 'b>(&'a self, first: &'b str) -> &'a str
    

If all of the above rules are satisfied, you are good to go. If the compiler fails to apply any of the above rules, it will stop and show a compile error, asking you to annotate the lifetime yourself.

For example, in the following function, there are two lifetime parameters 'a and 'b:

// 🚫 would not compile
fn split<'a, 'b>(source: &'a str, delimiter: &'b str) -> &??? str

In this case, the compiler could not figure out the output lifetime, so it will show a compile error.