Closures

Closure Syntax

A closure is an anonymous function expression written with vertical pipes (|params| body) that can be stored in a variable, passed as an argument, or returned from a function while capturing variables from its enclosing scope.

Anatomy of a Closure Expression

|x: i32, y: i32| -> i32 { x + y }
 ^^^^^^^^^^^^^^     ^^^   ^^^^^
   parameters      return  body
                    type

Unlike fn items, type annotations on closure parameters, the return type arrow (-> Type), and curly braces ({}) around a single-expression body are all optional when the compiler can infer them from context:

Form Syntax Notes
Fully annotated |x: i32| -> i32 { x + 1 } Explicit parameter type, return type, and block
Inferred types with block |x| { x + 1 } Braces kept; parameter and return types inferred
Single-expression body |x| x + 1 Braces omitted when the body is a single expression
Zero parameters || 42 Empty pipes || take no arguments
Ignored parameter |_| println!("called") Accepts one argument and discards it

Note that if you specify an explicit return type (-> T), the closure body must be wrapped in curly braces (|x| -> i32 { x + 1 }).

fn main() {
    let add_explicit = |a: i32, b: i32| -> i32 { a + b };
    let add_concise = |a, b| a + b;
    let greet = || "Hello, Rust!";

    println!("Explicit: {}", add_explicit(10, 20));
    println!("Concise:  {}", add_concise(5, 7));
    println!("Greet:    {}", greet());
}
Explicit: 30
Concise:  12
Greet:    Hello, Rust!

Multi-Statement Closure Bodies

When a closure performs multiple statements before returning a value, wrap the body in { ... } just like a regular function block:

fn main() {
    let format_tag = |raw: &str| {
        let trimmed = raw.trim();
        let lower = trimmed.to_lowercase();
        format!("#{lower}")
    };

    println!("{}", format_tag("  Rust2024  "));
}
#rust2024

Destructuring Patterns in Closure Parameters

Closure parameter lists support irrefutable patterns, allowing you to destructure tuples, structs, or references directly in the |...| header:

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let manhattan = |Point { x, y }: &Point| x.abs() + y.abs();
    let sum_pair = |(a, b): (i32, i32)| a + b;

    let p = Point { x: -4, y: 9 };
    println!("Manhattan distance: {}", manhattan(&p));
    println!("Pair sum:           {}", sum_pair((15, 25)));
}
Manhattan distance: 13
Pair sum:           40