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.
Basic closure syntax
Section titled “Basic closure syntax”fn main() { let add_one = |x: i32| x + 1; println!("{}", add_one(5));}Output:
6The 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 functionlet add_one_closure = |x: i32| x + 1; // the same thing as a closureRust can often infer the parameter and return types too, so you’ll frequently see closures written even shorter:
let add_one = |x| x + 1;Multi-line closures
Section titled “Multi-line closures”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));}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}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.
Where closures show up in practice
Section titled “Where closures show up in practice”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]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().