Iterators
| Iterator chains | |
| Lazy by default | |
| Collect results | |
| Find fold any |
Iterator chains
Iterators transform collections through small chained steps called adapters. Each adapter returns a fresh iterator, so steps snap together like pipe segments. The chain below keeps even numbers, doubles them, and adds everything up.
fn main() {
let nums = vec![1, 2, 3, 4];
let total: i32 = nums.iter().filter(|x| *x % 2 == 0).map(|x| x * 2).sum();
println!("{}", total);
}
Filter keeps what passes its test, map rewrites each survivor, and sum folds the rest into one number. No temporary vectors appear between steps. Reading the chain left to right tells the whole story.
Lazy by default
Adapters record a plan without running any of it. Real work starts only when something consumes the iterator, such as a for loop or sum. Building the plan below prints nothing until the loop pulls values through.
fn main() {
let nums = vec![1, 2, 3];
let it = nums.iter().map(|x| x * 2);
println!("built, nothing ran yet");
for n in it {
println!("{}", n);
}
}
Laziness lets long chains fuse into one pass with no middle storage. Infinite iterators stay safe too, since only requested items compute. Remember that an unused plan does nothing at all.
Collect results
Collect drains an iterator into a container such as a vector. The target type rarely needs naming because the next use reveals it. Words below gathers each number turned string into one growable list.
fn main() {
let nums = vec![1, 2, 3];
let words: Vec<String> = nums.iter().map(|n| n.to_string()).collect();
println!("{:?}", words);
}
The annotation pins the container when inference needs help, and turbofish works too. Strings, sets, and maps all collect from matching iterators. Collect is the standard bridge back to owned data.
Find fold any
Consumers finish the job in one value instead of another iterator. Find returns the first match, sum totals everything, and any reports whether some item passes. Found holds an option because the search may come up empty.
fn main() {
let nums = vec![1, 2, 3, 4];
let found = nums.iter().find(|x| *x == 3);
let sum: i32 = nums.iter().sum();
let big = nums.iter().any(|x| *x > 10);
println!("{:?} {} {}", found, sum, big);
}
Fold generalizes sum with a starting value and a combining closure. Find borrows the match instead of copying it out. Scan the Iterator docs for the rest, since dozens of small consumers await there.
Next: Smart pointers
Article author: Arthur Isaev