Nugget 11

Home

Consuming Your Iterator

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]

Math Consumers

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.).

Boolean Consumers

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.

Search Consumers

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.

Quick Reference

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

Key Takeaways