On this page
Iterator and Closures
Iterator is Rust’s most successful abstraction—adaptors like map/filter/chain are lazy (not invoked, not executed until needed), and compile down to machine code equivalent to hand-written loops (zero-cost). The three closure traits Fn/FnMut/FnOnce correspond to three capture modes, and collect gathers iterators into containers—chained operations go from readable to zero-cost in one step.
The Iterator trait: The root of all iteration
next() is the only method that must be implemented. All other methods—map, filter, take, fold, collect—are default implementations based on next(). This means that as long as you implement next(), your type automatically gains access to the entire iterator ecosystem.
Lazy Evaluation: Iterators do nothing until "driven"
let v: =
.filter // Does not happen — just builds the chain
.map // Does not happen
.take // Does not happen
.collect; // Now! All adaptors are "driven"
// → [0, 4, 8]
This code does not process any elements until collect() is called. When collect() calls next(), it requests from take, which requests from map, which requests from filter, which requests from 0..10—forming a "pull" chain. This is fundamentally different from eager evaluation (such as Python list comprehensions).
Key Adaptors
| adaptor | Purpose | When triggered |
|---|---|---|
map | Transform each element | lazy |
filter | Keep elements that satisfy a condition | lazy |
take(n) | Take the first n elements then stop | lazy |
skip(n) | Skip the first n elements | lazy |
enumerate | Attach an index (index, item) | lazy |
chain | Concatenate two iterators | lazy |
flat_map | Expand each element into an iterator | lazy |
fold | Accumulate (reduce) | eager (consumes the iterator) |
collect | Collect into a collection | eager |
The Three Closure Traits: FnOnce → FnMut → Fn
These three traits form a constraint chain:
FnOnce: Can be called only once — consumes captured values (ownership transfer)
FnMut: `&mut self` — can modify captured values, can be called multiple times
Fn: `&self` — read-only capture, can be called multiple times, most general
- All closures implement
FnOnceby default. - If a closure does not consume captured values → it also implements
FnMut. - If a closure does not modify captured values → it also implements
Fn.
let s = Stringfrom;
let f = ; // s is moved into the closure — this is a FnOnce
// f() can only be called once — after calling, s is consumed, and f can no longer be called
let mut v = vec!;
let mut f = ; // Modifies v — FnMut (can be called multiple times)
let x = 42;
let f = ; // Read-only — Fn (most general)
Zero-cost Iteration
In release mode, iterator chains are typically "fused" by the compiler into a single loop—continuous calls to map, filter, collect are optimized into an equivalent for loop, with no extra allocations and no virtual function calls. This is how Rust’s zero-cost abstraction manifests in iterators.
References
- Rust Book: Chapter 13
- Rust Reference: Fn traits, Iterator
Keywords: Iterator, lazy evaluation, collect, Fn, FnMut, FnOnce, adaptor, zero-cost