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.