What Iterator does

The trait that powers Rust's functional pipelines — lazy, zero-cost, stack-allocated.

As a trait, Iterator defines an interface that other types can implement. Code generic over T: Iterator can call any of its methods on values of any implementing type. The compiler monomorphises generic uses for zero-cost dispatch, while dyn Iterator opts into runtime dispatch with a vtable. The full canonical path is std::iter::Iterator; bring it into scope with use std::iter::Iterator; or refer to it by its full path.

When to use it

Reach for Iterator any time you transform or aggregate a sequence: map, filter, fold, sum, collect. Most adapters are zero-cost — the compiler inlines them into a single tight loop equivalent to hand-written imperative code.

Annotated examples

Iterator adapter chain: filter + map + sum

fn sum_squares_of_evens(nums: &[i32]) -> i32 {
    nums.iter()
        .filter(|&&n| n % 2 == 0)   // keep only evens
        .map(|&n| n * n)            // square them
        .sum()                       // fold into a single i32
}

fn main() {
    assert_eq!(sum_squares_of_evens(&[1, 2, 3, 4, 5]), 4 + 16);
}

A chain like this compiles to one tight loop — no intermediate Vec, no allocations. Iterator chains are usually as fast as hand-written for-loops, and easier to reason about.

For deeper background, see the canonical Rust patterns reference for the broader context behind this section.

collect into different containers based on the type annotation

use std::collections::HashSet;

fn dedupe<I: IntoIterator<Item = i32>>(items: I) -> HashSet<i32> {
    // collect picks its target by the type annotation on the binding
    // or the function return type. Same source, three possible outputs.
    items.into_iter().collect()
}

fn main() {
    let unique: HashSet<i32> = dedupe(vec![1, 2, 2, 3, 3, 3]);
    assert_eq!(unique.len(), 3);
}

collect can build any type implementing FromIterator: Vec, HashSet, HashMap, String, even your own types if you implement the trait.

Common pitfalls

Iterators are lazy — calling `.map()` on its own does nothing until a consuming method (collect, sum, fold, count, for_each, for-loop) drives them. A common bug is writing `things.iter().map(|x| println!(...));` and wondering why nothing prints — the closure never runs because nothing pulls from the iterator.

For deeper background, see an in-depth Rust idioms cheat sheet for the broader context behind this section.

Performance & threading notes

Generic uses (`T: Iterator`) are monomorphised — each concrete T gets its own specialised function, with no virtual-dispatch overhead. `dyn Iterator` adds a single indirection through a vtable, which is fast but blocks some compiler optimisations.