C.W.K.
Stream
Lesson 06 of 06 · published

Real Iterator Chains

~11 min · collections, iterators, collect, fold

Level 0Rust Curious
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

Now the payoff: the iterator vocabulary that turns ten-line imperative loops into one declarative chain. These are the patterns you'll reach for daily once they're in your fingers.

collect: build a collection

collect consumes an iterator into a collection — a Vec, a String, a HashMap, whatever you annotate. It's the universal 'turn this pipeline back into data' operation. A type annotation on the binding, or the turbofish collect::<Vec<_>>(), tells it what to build.

enumerate, zip, chain

enumerate pairs each item with its index — the right way to get an index without a manual counter. zip walks two iterators in lockstep into pairs. chain concatenates two iterators end to end. Together they replace a whole category of fiddly index manipulation.

enumerate beats a manual index counter. Instead of let mut i = 0; for x in &v { ...; i += 1; }, write for (i, x) in v.iter().enumerate(). No counter to forget to increment, no off-by-one, and the intent is explicit. It's the single most common iterator cleanup clippy suggests.

fold: the general reducer

fold(initial, |acc, item| ...) threads an accumulator through every element — sum, product, building a string, computing a max are all folds. When no specialized consumer fits, fold is the general tool. Understanding it means you can express almost any aggregation as one expression.

This is idiomatic Rust

Reaching for an iterator chain before a manual loop is one of the clearest markers of fluent Rust. The chains are declarative, bug-resistant (no index math), and zero-cost. When you catch yourself writing let mut result = vec![]; for ... { result.push(...) }, ask whether map+collect says it more clearly.

Code

enumerate, collect-into-map, and fold·rust
use std::collections::HashMap;

fn main() {
    let words = ["apple", "banana", "cherry"];

    // enumerate: index without a manual counter
    for (i, w) in words.iter().enumerate() {
        println!("{i}: {w}");
    }

    // collect into a HashMap of word -> length
    let lengths: HashMap<&str, usize> =
        words.iter().map(|&w| (w, w.len())).collect();
    println!("{:?}", lengths.get("banana")); // Some(6)

    // fold: general-purpose accumulation
    let total_len = words.iter().fold(0, |acc, w| acc + w.len());
    println!("{total_len}"); // 17
}

External links

Exercise

Given two Vecs — names and ages — use zip to pair them, filter to keep adults (age >= 18), and collect into a Vec<(String, u32)> (or a HashMap). Then rewrite a sum-of-lengths loop as a single fold. Which loops in your past code could have been one chain?
Hint
names.iter().zip(ages.iter()).filter(|(_, &age)| age >= 18).collect() does the join-and-filter in one expression. fold generalizes any accumulate-into-one-value loop.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.