← Back to Rust Course | Chapter 4: Functions | Lesson 4 of 6

Closures Basics

A closure is a small, portable function you can create on the spot that remembers things from around where it was written.
Syntax
rust
let name = |param| expression;
let name = |param: Type| -> ReturnType {
    // body
};

Defining a Closure

A closure is written using pipes | | around its parameter list, followed by an expression or block. Closures can be stored in a variable and then called just like a function.

Example: Defining a Closure

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `add_one`, set to `|x: i32| x + 1`
    let add_one = |x: i32| x + 1;
    // Print "{}" to the console, substituting in `add_one(5)` (with a trailing newline)
    println!("{}", add_one(5));
}

Capturing Variables from the Environment

Unlike regular functions, closures can directly use variables from the scope where they were defined, without needing to receive them as parameters.

Example: Capturing Variables from the Environment

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `multiplier`, set to `3`
    let multiplier = 3;
    // Declare an immutable variable `multiply`, set to `|x: i32| x * multiplier`
    let multiply = |x: i32| x * multiplier;
    // Print "{}" to the console, substituting in `multiply(7)` (with a trailing newline)
    println!("{}", multiply(7));
}

Type Inference in Closures

Closures typically don't need explicit parameter or return types annotated -- Rust infers them from how the closure is used, keeping closure syntax compact.

Example: Type Inference in Closures

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `square`, set to `|x| x * x`
    let square = |x| x * x;
    // Declare an immutable variable `result` (an integer), set to `square(6)`
    let result: i32 = square(6);
    // Print "{}" to the console, substituting in `result` (with a trailing newline)
    println!("{}", result);
}

Multi-line Closure Bodies

When a closure needs more than one expression, its body can be a full block in curly braces, just like a function body.

Example: Multi-line Closure Bodies

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `describe`, set to `|n: i32| {`
    let describe = |n: i32| {
        // Declare an immutable variable `kind`, set to `if n % 2 == 0 { "even" } else { "odd" }`
        let kind = if n % 2 == 0 { "even" } else { "odd" };
        format!("{} is {}", n, kind)
    };
    // Print "{}" to the console, substituting in `describe(9)` (with a trailing newline)
    println!("{}", describe(9));
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Forgetting closures can capture variables from their surrounding scope automatically, unlike regular fn functions.
  2. Writing unnecessary type annotations on every closure parameter, when Rust can usually infer them from usage.
  3. Confusing closure syntax |x| x + 1 with a bitwise OR expression when reading unfamiliar code.
Chapter Summary
  • Closures are anonymous functions written with pipes around parameters, like |x| x + 1.
  • Closures can capture variables from the environment they were defined in.
  • Closure parameter and return types are usually inferred, unlike regular function definitions.
  • Closures can be stored in variables and passed around like values.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.