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

Reference Lifetime Elision in Closures

Understand the unique elision rules for anonymous functions.

In this lesson, you will learn why Rust handles lifetime elision differently for closures compared to standard functions and how this impacts your code.

The Closure Distinction

You are already familiar with how Rust’s lifetime elision rules automatically fill in missing lifetimes for functions to keep your code concise. However, closures—anonymous functions—behave differently. Because closures are often defined inline and capture their environment, the compiler is much stricter.

Crucially, closures do not support lifetime elision for their parameters.

If you define a function with an argument &str, the compiler can infer the lifetimes based on the rules you’ve learned previously. If you try to do the same inside a closure, the compiler will demand that you be explicit if it cannot determine the relationship between inputs and outputs.

Why the difference?

Closures are represented internally as structs that implement a trait (Fn, FnMut, or FnOnce). When you pass a reference into a closure, that reference is a parameter of the call method of that trait. Because these traits are generic, the compiler cannot "guess" the lifetime bounds as easily as it can with a standalone function definition.

Consider this example:

// This works because of standard function elision
fn print_str(s: &str) { println!("{}", s); }

// This requires explicit lifetimes if the compiler gets confused!
let print_closure = |s: &str| { println!("{}", s); };

While simple closures often compile, you will quickly encounter "lifetime may not live long enough" errors the moment you try to return a reference from a closure or store it in a struct. In those cases, you cannot rely on the "magic" shorthand you use in standard fn definitions. You must annotate the lifetimes explicitly within the closure's signature or rely on the compiler’s ability to infer bounds from the captured environment.

If you find yourself struggling with a closure’s borrow checker error, the first step is to stop assuming the compiler will elide the lifetime and instead provide explicit annotations to guide the borrow checker.

Key Takeaway: Unlike standard functions, closures do not benefit from lifetime elision rules and will frequently require explicit lifetime annotations to resolve complex borrowing relationships.