Course contentsShow
← Rust
Lesson 350 of 1,9104. Lifetimes and Advanced OwnershipFree lesson

Explicit Lifetime Annotation Syntax

Annotate functions to bridge the gap between input and output reference lifetimes.

In this lesson, you will learn how to use explicit lifetime annotations to help the Rust compiler understand the relationship between the lifetimes of references passed into a function and the references returned by it.

The Problem: The Borrow Checker's Blind Spot

Normally, the borrow checker is excellent at tracking how long references live. However, when a function takes two references and returns one, the compiler often doesn't know which input reference the output is tied to. Is the returned reference valid for as long as the first input, the second, or both? Because the compiler refuses to guess, it requires us to provide a "hint" using lifetime annotations.

Adding the Annotations

Lifetime annotations don't change how long a value lives; they simply describe the relationship between the scopes of multiple references. We use an apostrophe followed by a name (usually 'a) to label the lifetime.

Consider this function that returns the longer of two string slices:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

Here is what is happening:

  1. Declaration: <'a> declares a lifetime parameter 'a for the function.
  2. Input Linking: By using 'a in x: &'a str and y: &'a str, we are telling the compiler: "The input x and the input y must both live at least as long as this scope 'a."
  3. Output Linking: The return type -> &'a str tells the compiler: "The reference I return will be valid for at least as long as the scope 'a."

By annotating these, you are guaranteeing that the returned reference will be valid as long as the shortest of the two input references. If you pass in two references that only live for a short scope, the returned value is restricted to that same short scope. If you try to use the returned reference after one of the inputs has been dropped, the borrow checker will catch it, ensuring memory safety.

Key Takeaway: Explicit lifetime annotations describe the relationship between the lifetimes of multiple references so the compiler can verify that return values remain valid.