Iterators

fold() and reduce()

The .fold() and .reduce() consumer methods eagerly collapse an entire iterator into a single value by repeatedly applying a combining closure (FnMut(Acc, Item) -> Acc) to an accumulator and each element.

Signatures and Comparison

fn fold<B, F>(self, init: B, f: F) -> B
where
    Self: Sized,
    F: FnMut(B, Self::Item) -> B;

fn reduce<F>(self, f: F) -> Option<Self::Item>
where
    Self: Sized,
    F: FnMut(Self::Item, Self::Item) -> Self::Item;
Aspect .fold(init, f) .reduce(f)
Initial accumulator Explicitly passed via init: B Uses the first element of the iterator
Accumulator type Any type B (can differ from Self::Item) Must be Self::Item
Return type B (returns init if iterator is empty) Option<Self::Item> (None if iterator is empty)
[10, 20, 30].into_iter().fold(0, |acc, x| acc + x)

  init = 0
    ├── f(0, 10)  -> 10
    ├── f(10, 20) -> 30
    └── f(30, 30) -> 60 (returned)

Accumulating Into a Different Type with .fold()

Because .fold() allows the accumulator type B to differ from Self::Item, it can build a struct, tuple, or formatted string in a single pass:

#[derive(Debug, Default)]
struct Stats {
    count: usize,
    sum: i64,
    min: i64,
    max: i64,
}

fn main() {
    let readings = [18_i64, 42, 7, 29, 35];

    let stats = readings.into_iter().fold(
        Stats {
            count: 0,
            sum: 0,
            min: i64::MAX,
            max: i64::MIN,
        },
        |acc, x| Stats {
            count: acc.count + 1,
            sum: acc.sum + x,
            min: acc.min.min(x),
            max: acc.max.max(x),
        },
    );

    println!("{stats:?}");
}
Stats { count: 5, sum: 131, min: 7, max: 42 }

Folding Without an Explicit Initial Value Using .reduce()

When the accumulator has the same type as Self::Item and no natural identity value exists, .reduce() uses the first item as the seed and returns None on an empty iterator:

fn main() {
    let words = ["rust", "2024", "edition"];
    let empty: [&str; 0] = [];

    let joined = words
        .into_iter()
        .map(String::from)
        .reduce(|acc, word| format!("{acc}-{word}"));

    let empty_result = empty
        .into_iter()
        .map(String::from)
        .reduce(|acc, word| format!("{acc}-{word}"));

    println!("Joined: {joined:?}");
    println!("Empty:  {empty_result:?}");
}
Joined: Some("rust-2024-edition")
Empty:  None

Fallible Accumulation with .try_fold()

When the combining operation can fail or short-circuit early, use .try_fold(init, f), where f returns Result<B, E> or Option<B>. As soon as f returns Err(e) or None, .try_fold() stops polling the iterator and returns that error immediately.