Closures

Closures and Iterators

Closures and iterators work together across the standard library: iterator adapters and consumers accept FnMut closures to transform, filter, and fold sequences lazily, compiling down to tight machine loops with no intermediate allocations.

Closure Signatures Across Common Iterator Methods

Because iterator methods invoke their callback sequentially on each element, they bound their closure parameter by FnMut:

Iterator Method Closure Bound Role of Closure
.map(f) F: FnMut(Self::Item) -> B Transforms each element Self::Item into a new value B
.filter(p) P: FnMut(&Self::Item) -> bool Inspects each element by shared reference &Self::Item and keeps true matches
.filter_map(f) F: FnMut(Self::Item) -> Option<B> Filters and transforms in one step, keeping unwrapped Some(b) values
.flat_map(f) F: FnMut(Self::Item) -> U (U: IntoIterator) Maps each element to an iterable and flattens the results
.fold(init, f) F: FnMut(B, Self::Item) -> B Combines accumulator B and each item into an updated accumulator
.any(p) / .all(p) P: FnMut(Self::Item) -> bool Short-circuiting boolean test across elements
.for_each(f) F: FnMut(Self::Item) Executes a side effect for each element

Notice the receiver difference between .map and .filter: .map passes Self::Item by value to the closure, whereas .filter passes &Self::Item by shared reference because .filter must preserve the item to yield it downstream if the predicate returns true.

Chaining Closures in an Iterator Pipeline

#[derive(Debug)]
struct Order {
    id: u32,
    amount_cents: u64,
    paid: bool,
}

fn main() {
    let min_cents: u64 = 2_000;
    let orders = vec![
        Order { id: 1, amount_cents: 1_500, paid: true },
        Order { id: 2, amount_cents: 4_500, paid: true },
        Order { id: 3, amount_cents: 8_000, paid: false },
        Order { id: 4, amount_cents: 3_200, paid: true },
    ];

    let mut qualified_count = 0usize;

    // Captures `min_cents` by `&u64` and `qualified_count` by `&mut usize`:
    let total_cents: u64 = orders
        .iter()
        .filter(|order| order.paid && order.amount_cents >= min_cents)
        .map(|order| {
            qualified_count += 1;
            order.amount_cents
        })
        .sum();

    println!("Qualified orders: {qualified_count}, total cents: {total_cents}");
}
Qualified orders: 2, total cents: 7700

Returning a Lazy Iterator That Captures a Closure

When returning an iterator adapter chain (such as iter.map(move |x| ...)) from a function, use move on the closure so any local variables captured by the closure are moved into the returned Map struct:

fn scaled_range(start: i32, end: i32, factor: i32) -> impl Iterator<Item = i32> {
    (start..=end).map(move |x| x * factor)
}

fn main() {
    let values: Vec<i32> = scaled_range(1, 5, 10).collect();
    println!("{values:?}");
}
[10, 20, 30, 40, 50]