Rust Consuming Iterators
A consuming iterator method pulls items through a chain and returns a final answer. sum, count, and collect are consumers.
sum and count finish a chain
sum adds the items. count counts them. Both pull until the iterator is empty. In short, a consumer pulls items through the chain and returns the final answer:
let total: i32 = (1..=4).sum();
println!("sum = {total}, count = {}", (1..=4).count());Multiply everything with product
sum adds. product multiplies. It is the natural way to write a factorial:
let fact: i32 = (1..=5).product();
println!("5! = {fact}");collect builds the collection you ask for
collect gathers items into the type you name — here, single characters become one String:
let word: String = ['r', 'u', 's', 't'].into_iter().collect();
println!("{word}");find and any answer questions
find returns the first item that passes, as an Option. any answers true or false:
let first_even = [1, 3, 4].iter().find(|&&n| n % 2 == 0);
let any_big = [1, 3, 4].iter().any(|n| *n > 10);
println!("{first_even:?} {any_big}");Jump ahead with nth, finish with last
nth(2) skips two items and returns the third — the skipped ones are consumed. last() pulls everything and keeps only the final item:
let mut it = vec!["a", "b", "c", "d"].into_iter();
println!("nth(2) = {:?}", it.nth(2));
println!("next = {:?}", it.next());
let last: Option<i32> = (5..9).last();
println!("last = {last:?}");min and max without a key
When the items compare directly, plain min and max need no key closure. Both still return Option. An empty iterator has no winner:
let low: Option<i32> = vec![9, 4, 7].into_iter().min();
let high: Option<i32> = vec![9, 4, 7].into_iter().max();
println!("min = {low:?} max = {high:?}");Example
fn main() {
let total: i32 = (1..=100).filter(|n| n % 3 == 0).sum();
println!("sum of multiples of 3 up to 100 = {}", total);
let (evens, odds): (Vec<i32>, Vec<i32>) = (1..=6).partition(|n| n % 2 == 0);
println!("evens {:?} odds {:?}", evens, odds);
}Key points
- Use fold(start, f) for a custom accumulation.
- sum is a fold in disguise.
- Use for_each(f), or a plain for loop, when you only need side effects like printing
- find hands the closure a reference to the item, &Item.
- Over .iter() the item already is a reference.
- So the pattern doubles up as |&&x|.
- find gives back the found reference.
- position hands the item itself and gives back its index number.
- Use min_by_key(f) and max_by_key(f) to find the item with the smallest or largest measured value.
- Both return an Option.
- An empty iterator has no winner.
- A consumer ends the pipeline.
In this example, the range 1..=100 is filtered to multiples of 3, and sum() adds them: 1683. Below, partition walks 1..=6 once and sorts each number into one of two Vecs by a simple test, "is it even?". The result is evens [2, 4, 6] and odds [1, 3, 5]. Notice that both answers came from one pass of pulling — consumers never need the items twice.
Note
collect can even gather Results: collecting into Result<Vec<T>, E> stops at the first Err.
One failure fails the whole collection — a neat way to validate a list of inputs.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What happens when you collect an iterator of Results into a Result<Vec<T>, E>?