Closures
Closures
Closures are anonymous functions that can capture values from their surrounding scope.
Syntax
let add = |x, y| x + y; // type inferred
let square = |x: i32| x * x; // explicit type
let always_one = || 1; // no parameters
Capture Semantics
Rust closures capture variables from their environment in three ways, and the compiler picks the least restrictive mode that works:
1. Borrow immutably (Fn) — the closure only reads the captured value:
let name = String::from("Alice");
let greet = || println!("Hello, {}", name); // borrows &name
greet();
greet(); // can call multiple times
println!("{}", name); // name still usable
2. Borrow mutably (FnMut) — the closure modifies the captured value:
let mut count = 0;
let mut inc = || { count += 1; count };
inc(); // count is now 1
inc(); // count is now 2
3. Move / consume (FnOnce) — the closure takes ownership:
let name = String::from("Alice");
let consume = || { drop(name); }; // moves name into closure
consume(); // name is dropped
// consume(); ← ERROR: cannot call FnOnce twice
The move Keyword
move forces the closure to take ownership of all captured variables, even if it only reads them. This is essential when the closure outlives the scope it was created in:
fn make_greeter(name: String) -> impl Fn() -> String {
move || format!("Hello, {}!", name) // must move: name would be dropped otherwise
}
Closure Trait Hierarchy
Every closure implements FnOnce. If it doesn't consume captures, it also implements FnMut. If it doesn't mutate captures, it also implements Fn:
Fn ⊂ FnMut ⊂ FnOnce
A function accepting impl FnOnce can take any closure. A function requiring impl Fn only accepts closures that borrow immutably.
Higher-Order Functions
Functions that accept closures use trait bounds:
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
f(x)
}
apply(|x| x * 2, 5); // 10
Returning Closures
fn make_adder(n: i32) -> impl Fn(i32) -> i32 {
move |x| x + n
}
let add5 = make_adder(5);
add5(3); // 8
Your Task
apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32— applies f to x.apply_n_times<F: Fn(i32) -> i32>(f: F, x: i32, n: u32) -> i32— applies f to x n times.make_adder(n: i32) -> impl Fn(i32) -> i32— returns a closure that adds n.make_multiplier(n: i32) -> impl Fn(i32) -> i32— returns a closure that multiplies by n.make_counter() -> impl FnMut() -> i32— returns a closure that returns an incrementing count (1, 2, 3, ...) each time it is called. This exercisesFnMutcapture semantics.consume_and_length(s: String) -> impl FnOnce() -> usize— returns a closure that movessinto itself and returns its length. This exercisesFnOnce/movecapture semantics.