Iterator + Closure Patterns
Closures power iterator adapters for expressive, lazy data pipelines.
Recipe
fn active_names(users: &[(&str, bool)]) -> Vec<String> {
users.iter()
.filter(|(_, active)| *active)
.map(|(name, _)| name.to_uppercase())
.collect()
}When to reach for this: Transforming collections without intermediate mutation.
Working Example
#[derive(Debug)]
struct Order { total: u32, vip: bool }
fn discount_summary(orders: &[Order]) -> (u32, u32) {
let vip_total: u32 = orders.iter()
.filter(|o| o.vip)
.map(|o| o.total)
.sum();
let regular: u32 = orders.iter()
.filter(|o| !o.vip)
.map(|o| o.total / 2)
.sum();
(vip_total, regular)
}What this demonstrates:
- Multiple passes acceptable for clarity (or combine with fold)
- Closures in
filter/map - Collect to sum consumer
Deep Dive
Prefer filter_map over filter+map. Use fold for single-pass aggregation. then (1.51+) chains Option steps.
Gotchas
- Cloning in map -
|s| s.clone(). Fix: Use references earlier. - Mutable closure in parallel rayon -
FnnotFnMut- sync only. - Long closure chains - Extract named functions.
- needless collect - clippy warning.
- move closure in loop - May force move entire env each iter.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
for loop | Complex break/continue | Straight pipeline |
| SQL/query engine | Large data | In-memory small vec |
rayon | CPU parallel | I/O bound |
FAQs
filter_map?
Map and drop Nones in one.flat_map?
Flatten nested iterators.scan?
Stateful map with accumulator.inspect?
Debug tap in pipeline.chain Option?
and_then on Option not iterator.windows chunks?
On slices via windows/chunks adapters on arrays.sort_by closure?
FnMut compare.group_by unstable?
itertools group_by stable crate.polars?
Lazy expressions similar spirit.readability?
Break into named steps if >5 adapters.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+.