Nugget 11
Home
map() and filter() are lazy — they just describe work.
These methods actually do the work: they pull items from the iterator
until it's exhausted and return a final value.
collect() — The Swiss Army Knife
collect() is the most flexible consumer. It converts an iterator
into almost any collection:
let nums = 1..=5;
let vec: Vec<i32> = nums.clone().collect();
let set: std::collections::HashSet<i32> = nums.clone().collect();
let deq: std::collections::VecDeque<_> = nums.clone().collect();
let map: std::collections::HashMap<_, _> =
(1..=3).map(|x| (x, x * 10)).collect(); // From tuples
You must specify the target type — either with a type annotation or by using the result in a way that constrains the type:
let v1: Vec<i32> = (1..=5).collect(); // type annotation let v2 = (1..=5).collect::<Vec<_>>(); // turbofish let v3 = (1..=5).collect::<Vec<i32>>(); // explicit turbofish // all three produce vec![1, 2, 3, 4, 5]
let nums = [1, 2, 3, 4, 5]; // sum — adds up numeric items let total: i32 = nums.iter().sum(); assert_eq!(total, 15); // product — multiplies (via fold, but there's no product() — use fold!) let product: i32 = nums.iter().product(); assert_eq!(product, 120); // count — how many items let count = nums.iter().count(); assert_eq!(count, 5);
sum() and product() need a type annotation because
they work for any numeric type (i32, f64, etc.).
These check every item against a condition and short-circuit:
let nums = [1, 2, 3, 4, 5]; // any — does ANY item satisfy the condition? (stops at first match) let has_even = nums.iter().any(|x| x % 2 == 0); assert_eq!(has_even, true); // all — does EVERY item satisfy the condition? (stops at first failure) let all_positive = nums.iter().all(|x| x > &0); assert_eq!(all_positive, true); let all_even = nums.iter().all(|x| x % 2 == 0); assert_eq!(all_even, false); // 1, 3, 5 are odd // Short-circuiting: if the 3rd item fails all(), items 4 & 5 never run.
let nums = [10, 20, 30, 40, 50]; // find — returns the first matching item let found = nums.iter().find(|x| x > &&25); assert_eq!(found, Some(&30)); // position — returns the index of the first match let idx = nums.iter().position(|x| x > &25); assert_eq!(idx, Some(2)); // index 2 = &30 // Both short-circuit at the first match.
fold() — The General-Purpose Accumulator
When none of the above fit, fold() can do anything. It takes an
initial value and a closure that updates it with each item:
let nums = [1, 2, 3, 4, 5];
// Sum manually: start at 0, add each item
let sum = nums.iter().fold(0, |acc, x| acc + x);
assert_eq!(sum, 15);
// Product: start at 1, multiply each item
let product = nums.iter().fold(1, |acc, x| acc * x);
assert_eq!(product, 120);
// Max: start at i32::MIN, keep the larger
let max = nums.iter().fold(i32::MIN, |acc, x| acc.max(*x));
assert_eq!(max, 5);
// Build a custom structure
let csv_line = (1..=4).fold(String::new(), |acc, x| {
if acc.is_empty() { format!("{x}") }
else { format!("{acc},{x}") }
});
assert_eq!(csv_line, "1,2,3,4");
📐 fold vs reduce
reduce() is like fold() but starts from the first
element (no initial value). It returns Option because the
iterator might be empty. fold() is usually more practical
because you control the initial value.
for_each() — Side Effects
Use for_each() when you want to do something with each item but
don't need a return value:
let names = ["Alice", "Bob", "Charlie"];
names.iter().for_each(|name| {
println!("Hello, {name}!");
});
// Prints each greeting — returns ()
💡 for_each vs for
The regular for loop is more idiomatic for side effects.
for_each() is useful at the end of a long chain where you
don't want to break it into a loop.
| Consumer | Returns | When to use |
|---|---|---|
collect() |
Collection | "I want a Vec/HashSet/etc" |
sum() |
Number | "Add them all up" |
count() |
usize |
"How many items?" |
any() |
bool |
"Does at least one match?" |
all() |
bool |
"Do all match?" |
find() |
Option<&T> |
"Find the first matching item" |
position() |
Option<usize> |
"Find the index of the first match" |
fold() |
Any | "I need a custom accumulation" |
for_each() |
() |
"Do something for each item (side effects)" |
collect() is the most flexible — converts to any collection type.any() and all() short-circuit, saving work on large collections.fold() is the universal accumulator — if none of the others fit, fold() can do it.