Iterator Adapters
Adapters transform iterators lazily: map, filter, take, skip, zip, flat_map, enumerate, peekable.
Recipe
fn main() {
let out: Vec<i32> = (0..10)
.filter(|n| n % 2 == 0)
.map(|n| n * 2)
.collect();
println!("{:?}", out);
}When to reach for this: Functional-style transforms without intermediate Vec unless needed.
Working Example
fn parse_lines(lines: &str) -> Result<Vec<i32>, std::num::ParseIntError> {
lines.lines()
.map(|l| l.trim().parse())
.collect()
}
fn main() {
let data = "1\n2\n3\n";
println!("{:?}", parse_lines(data));
}What this demonstrates:
lines()adapter on&strmap+collectintoResult<Vec<_>, _>- Lazy until
collect
Deep Dive
Chain order matters: filter before map avoids useless work. flat_map flattens Iterator<Item=impl Iterator>.
Gotchas
- Multiple passes on cold iterator - Consumed after first pass. Fix:
collectthen reuse vec. - Closures capturing references - Lifetime limits. Fix:
moveclosure or owned data. - Infinite zip shorter - Zip ends on shortest. Fix:
zip_longestcrates if needed. - filter_map vs map+filter - Single pass with
filter_map. - Collect type inference - Turbofish needed sometimes.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
for loop | Complex control flow | Simple transforms |
rayon par_iter | CPU parallel | I/O bound |
| Manual index | Neighbor access | Clean adapters exist |
FAQs
lazy?
Until consume adapter.chain?
Concat iterators.cycle?
Infinite repeat.scan?
Stateful map.windows?
On slices not all iterators.inspect?
Side effect per item.tee?
Split iterator - needs itertools.async?
StreamExt adapters.performance?
LLVM often fuses loops.clippy?
needless_collect warns.Related
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.