Skip to content

Rust Closures

A closure is a small, unnamed function you can store in a variable and pass around. The thing that makes them different from regular functions is that they can “capture” variables from the scope they were created in.

fn main() {
let add_one = |x: i32| x + 1;
println!("{}", add_one(5));
}

Output:

6
▶ Try it Yourself

The pipes |x: i32| stand in for the parentheses a regular function would use. Compare the two side by side:

fn add_one_fn(x: i32) -> i32 { x + 1 } // a regular function
let add_one_closure = |x: i32| x + 1; // the same thing as a closure

Rust can often infer the parameter and return types too, so you’ll frequently see closures written even shorter:

let add_one = |x| x + 1;

For more than one expression, wrap the body in braces just like a function:

fn main() {
let describe = |n: i32| {
let kind = if n % 2 == 0 { "even" } else { "odd" };
format!("{n} is {kind}")
};
println!("{}", describe(7));
}
▶ Try it Yourself

Capturing variables from the surrounding scope

Section titled “Capturing variables from the surrounding scope”

Here’s the feature a regular function doesn’t have: a closure can use variables from wherever it was defined, without you passing them in explicitly:

fn main() {
let discount = 10;
let apply_discount = |price: i32| price - discount;
println!("{}", apply_discount(100)); // 90
println!("{}", apply_discount(50)); // 40
}
▶ Try it Yourself

discount isn’t a parameter of the closure — it’s just sitting in main’s scope, and the closure reaches out and uses it directly. A regular fn can’t do this; it would need discount passed in as an argument.

You won’t reach for closures much on their own — where they’re genuinely useful is passing custom behavior into another function, especially the iterator methods you’ll meet on the Iterators page:

fn main() {
let numbers = vec![1, 2, 3, 4, 5];
let doubled: Vec<i32> = numbers.iter().map(|n| n * 2).collect();
println!("{:?}", doubled);
}

Output:

[2, 4, 6, 8, 10]
▶ Try it Yourself

Here, |n| n * 2 is a closure passed straight into .map() — this pattern (a small closure driving a method like .map() or .filter()) is where you’ll actually use them day to day.

  • A closure is a small anonymous function: |params| expression.
  • Types are often inferred, so closures are usually shorter than an equivalent fn.
  • Unlike a regular function, a closure can capture variables from the scope it was defined in.
  • Closures are most useful passed into other functions — especially iterator methods like .map().