Course contentsShow
← Rust
Lesson 237 of 1,9103. Borrowing and ReferencesFree lesson

Writing Explicit Lifetime Annotations

Attach generic lifetime parameters to functions to link input and output lifetimes.

In this lesson, you will learn how to use explicit lifetime annotations to tell the Rust compiler exactly how the lifetimes of your input references relate to the lifetime of your output reference.

Why do we need these?

Up until now, the compiler has been performing "lifetime elision"—it automatically guesses the relationships between references for you. However, when a function accepts multiple references and returns one, the compiler often becomes uncertain about which input data the output refers to. Since Rust refuses to return a reference that might become invalid, it asks you to clarify the connection using lifetime annotations.

The Anatomy of an Annotation

A lifetime annotation doesn’t change how long a value lives; it just labels the relationship between references. We declare a generic lifetime parameter inside angle brackets <'a> (the tick is required) and then attach that label to our references.

Consider a function that picks 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
    }
}

Breaking it down

  1. The Declaration: We declare <'a> after the function name. This introduces the lifetime 'a as a generic parameter, much like how we use generic types.
  2. The Constraints: By labeling x, y, and the return type with 'a, we are telling the compiler: "The returned reference will live at least as long as both x and y."
  3. The Relationship: If you pass in two references with different scopes, 'a will be constrained to the smaller of the two. This ensures that the returned reference is never used after the memory it points to has been cleaned up.

If you omit these, the compiler cannot verify if the returned reference is safe, leading to an error. By adding these annotations, you are creating a "contract" that the function will always return a reference that is valid for the duration of the overlap of the inputs.

Key Takeaway: Explicit lifetime annotations are labels that define the scope relationship between input references and output references, allowing the borrow checker to guarantee that no dangling pointers are ever returned.