← Back to Rust Course | Chapter 14: Closures, Iterators & Async | Lesson 3 of 6

map, filter, and collect

map, filter, and collect let you transform, pick out, and finally gather items from a list, one clean step at a time.

Transforming with map

.map() applies a closure to every element of an iterator, producing a new iterator of the transformed results without modifying the original collection.

Example: Transforming with map

markup
fn main() {
    let numbers = vec![1, 2, 3, 4];
    let squared: Vec<i32> = numbers.iter().map(|n| n * n).collect();
    println!("{:?}", squared);
}

Selecting with filter

.filter() keeps only the elements for which the given closure returns true, discarding everything else from the resulting iterator.

Example: Selecting with filter

markup
fn main() {
    let numbers = vec![1, 2, 3, 4, 5, 6];
    let evens: Vec<&i32> = numbers.iter().filter(|&&n| n % 2 == 0).collect();
    println!("{:?}", evens);
}

Gathering Results with collect

.collect() consumes an iterator and gathers its elements into a concrete collection type, such as Vec<T> or a String, inferred from context or an explicit type annotation.

Example: Gathering Results with collect

markup
fn main() {
    let words = vec!["Rust", "is", "fun"];
    let joined: String = words.iter().map(|w| w.to_uppercase()).collect::<Vec<String>>().join(" ");
    println!("{}", joined);
}

Chaining map and filter Together

.map() and .filter() can be chained in sequence to express a multi-step transformation clearly and efficiently, since both are lazy and only run once .collect() consumes the pipeline.

Example: Chaining map and filter Together

markup
fn main() {
    let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8];
    let result: Vec<i32> = numbers.iter().filter(|&&n| n % 2 == 0).map(|n| n * 10).collect();
    println!("{:?}", result);
}
Common Mistakes
  1. Forgetting to call .collect() (or another consuming method) at the end of a chain, since .map()/.filter() alone produce a lazy iterator, not a final collection.
  2. Not annotating the target type for .collect() when it cannot be inferred, leading to a compile error about an ambiguous type.
  3. Chaining .filter() after .map() when filtering first would avoid transforming elements that will just be thrown away.
Chapter Summary
  • .map(closure) transforms each element of an iterator, producing a new iterator of transformed values.
  • .filter(closure) keeps only the elements for which the closure returns true.
  • .collect() consumes an iterator and gathers its items into a concrete collection, like Vec<T>.
  • These three methods are commonly chained together to express a full data transformation pipeline concisely.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.