Course contentsShow
← Rust
Lesson 54 of 1,9101. Rust Fundamentals and ToolingFree lesson

Function Closures and Captures

Implement anonymous functions that capture their environment using various closure traits.

In this lesson, you will learn how to create anonymous functions that "capture" variables from their surrounding scope to use them inside their logic.

What are Closures?

In Rust, closures are anonymous functions you can save in a variable or pass as arguments to other functions. Unlike standard functions defined with fn, closures can capture variables from the scope where they are defined. Think of a closure as a function that carries its own private "backpack" containing the data it needs from the outside world.

Capturing the Environment

A closure can capture variables in three ways: by reference, by mutable reference, or by moving ownership. Rust decides how to capture these variables automatically based on how you use them inside the closure.

A Simple Capture Example

fn main() {
    let multiplier = 2;

    // This closure captures 'multiplier' by reference
    let multiply = |x| x * multiplier;

    println!("{}", multiply(5)); // Prints 10
}

In the example above, the closure multiply accesses the variable multiplier from the main function's scope. Because we only read the value, Rust automatically captures it by immutable reference.

Mutable Captures

If you need your closure to modify a variable from the surrounding scope, you must declare the closure variable as mut and the closure will capture it mutably:

fn main() {
    let mut count = 0;

    // Use 'mut' so the closure can change 'count'
    let mut increment = || {
        count += 1;
        println!("Count is now: {}", count);
    };

    increment();
    increment();
}

The Move Keyword

Sometimes you want to take ownership of a variable rather than just borrowing it. This is useful when you need to pass a closure into a new thread or return it from a function. You can force this behavior by adding the move keyword before the closure definition:

let data = String::from("Hello");

// The 'move' keyword forces the closure to take ownership of 'data'
let consume = move || {
    println!("{}", data);
};

By using move, the closure effectively takes the "backpack" contents into its own memory space, ensuring the closure remains valid even if the original variable goes out of scope.

Key Takeaway: Closures are anonymous functions that can capture their surrounding environment, either by borrowing variables or by taking ownership of them via the move keyword.