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

Connecting References and Closures

Manage lifetime requirements when returning closures that capture references.

In this lesson, you will learn why returning a closure that captures a reference can trigger a compiler error and how to solve it.

The Lifetime Problem

When you write a closure that uses a variable from its outer scope, the closure "captures" that variable. If the variable is a reference, the closure now depends on that reference remaining valid.

The trouble starts when you try to return that closure from a function. Consider this:

fn get_greeter(name: &str) -> impl Fn() {
    || println!("Hello, {}!", name)
}

If you try to compile this, Rust will complain. Why? Because the name reference lives only as long as the get_greeter function call. When the function returns, name goes out of scope, but the closure is still trying to hold onto it. You are trying to return a "dangling" reference, and the borrow checker stops you to prevent a crash.

Moving vs. Borrowing

To fix this, you have two primary strategies:

  1. Move the value: If the closure doesn't need to borrow the original variable, you can use the move keyword. This forces the closure to take ownership of the data. The closure carries its own copy of the string, so it doesn't matter when the original function scope ends.

    fn get_greeter(name: String) -> impl Fn() {
        move || println!("Hello, {}!", name)
    }
    
  2. Specify lifetimes: If you absolutely must return a reference (for example, if the data lives in a global context or is passed in as a 'static reference), you must explicitly tell the compiler that the closure’s lifetime is tied to that reference. However, because closures are often complex types, the most common beginner approach is to avoid returning borrowed references inside closures by moving ownership into the closure instead.

By default, closures try to borrow. When returning a closure from a function, the borrow checker effectively sees you returning a "ticket" to a room that is about to be demolished. You must either bring the "furniture" (the data) inside the closure using move or ensure the data persists longer than the closure itself.

Key Takeaway: When a closure captures a local reference, that closure cannot outlive the variable it references; use the move keyword to transfer ownership into the closure if you need to return it from a function.