---
title: Iterator and Closures
url: https://doc.liz6.com/en/rust/10-standard-library-depth/01-iterator-and-closures
locale: en
area: rust
tags:
- Iterator
- lazy evaluation
- collect
- Fn
- FnMut
- FnOnce
- adaptor
- zero-cost
- rust
- standard-library-depth
date: 2026-06-30
modified: 2026-07-16
description: 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.
---

# 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

```rust
pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
    // 70+ methods have default implementations — all based on next()
}
```

`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"

```rust
let v: Vec<i32> = (0..10)
    .filter(|x| x % 2 == 0)         // Does not happen — just builds the chain
    .map(|x| x * 2)                  // Does not happen
    .take(3)                         // 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 `FnOnce` by 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`.

```rust
let s = String::from("hi");
let f = || s;                        // 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![1, 2, 3];
let mut f = || { v.push(4); };       // Modifies v — FnMut (can be called multiple times)

let x = 42;
let f = || println!("{}", x);        // 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*
