SyntaxStudy
Sign Up
Rust Iterator Adapters and Closures
Rust Beginner 1 min read

Iterator Adapters and Closures

Iterators and closures are deeply intertwined in Rust. The `Iterator` trait's adapter methods — `map`, `filter`, `flat_map`, `take_while`, `skip_while`, `scan`, `inspect`, `zip`, `enumerate`, `chain`, and many others — all accept closures that define the transformation or predicate. Because these adapters are lazy (they create a new iterator but do not execute anything until consumed), you can chain many adapters with no intermediate allocation. Terminal methods like `collect`, `sum`, `product`, `count`, `for_each`, `any`, `all`, `find`, `position`, `fold`, `reduce`, and `max_by_key` drive the iteration to completion. `collect` is especially powerful: it can produce a `Vec`, `HashMap`, `HashSet`, `String`, `BTreeMap`, or any other collection that implements `FromIterator`. The type of the collection is usually inferred from the context. Writing iterator-based code is idiomatic Rust: it is typically shorter, more expressive, and just as fast as an equivalent hand-written loop. The compiler can eliminate bounds checks, fuse adjacent adapters, and vectorise the resulting code. Learning to think in terms of iterator pipelines — source, zero or more adapters, one terminal — is a significant productivity multiplier for Rust programmers.
Example
use std::collections::HashMap;

fn main() {
    let words = vec!["apple", "banana", "cherry", "apricot", "blueberry", "avocado"];

    // Chain of adapters — no intermediate allocations
    let a_words_upper: Vec<String> = words.iter()
        .filter(|w| w.starts_with('a'))
        .map(|w| w.to_uppercase())
        .collect();
    println!("a-words: {:?}", a_words_upper);

    // fold — general reduction
    let total_len: usize = words.iter().fold(0, |acc, w| acc + w.len());
    println!("total char count: {total_len}");

    // flat_map — flatten nested iterables
    let letters: Vec<char> = words.iter()
        .flat_map(|w| w.chars())
        .filter(|c| *c == 'a')
        .collect();
    println!("count of 'a': {}", letters.len());

    // enumerate + collect into HashMap
    let index_map: HashMap<usize, &str> = words.iter()
        .enumerate()
        .map(|(i, &w)| (i, w))
        .collect();
    println!("word at index 2: {}", index_map[&2]);

    // zip two iterators
    let nums = vec![1u32, 2, 3];
    let labels = vec!["one", "two", "three"];
    let zipped: Vec<_> = nums.iter().zip(labels.iter()).collect();
    println!("zipped: {:?}", zipped);

    // scan — accumulating state mid-stream
    let running: Vec<u32> = (1..=5)
        .scan(0u32, |state, x| { *state += x; Some(*state) })
        .collect();
    println!("running sums: {:?}", running);

    // any / all
    println!("any > 5 chars: {}", words.iter().any(|w| w.len() > 5));
    println!("all non-empty: {}", words.iter().all(|w| !w.is_empty()));
}