| name | rust-iterators |
| description | Use Rust iterators effectively, understand iterator adaptors, and write efficient iterator chains. Use when working with collections, transforming data, filtering, mapping, or collecting results. Handles iterator adaptors, lazy evaluation, collecting strategies, and performance considerations. |
Rust Iterators
Guidelines for using Rust iterators effectively and efficiently.
When to Use This Skill
- Working with collections
- Transforming data
- Filtering and mapping
- Collecting results
- Writing iterator chains
- Understanding lazy evaluation
Basic Iterator Usage
Creating Iterators
let vec = vec![1, 2, 3];
let iter = vec.iter();
let mut vec = vec![1, 2, 3];
let iter = vec.iter_mut();
let iter = vec.into_iter();
Basic Operations
for item in vec.iter() {
println!("{}", item);
}
let doubled: Vec<i32> = vec.iter().map(|x| x * 2).collect();
let sum: i32 = vec.iter().sum();
let count = vec.iter().count();
Iterator Adaptors
Map
let doubled: Vec<i32> = vec![1, 2, 3]
.iter()
.map(|x| x * 2)
.collect();
Filter
let evens: Vec<i32> = vec![1, 2, 3, 4, 5]
.iter()
.filter(|x| x % 2 == 0)
.collect();
Filter Map
let results: Vec<i32> = vec![Some(1), None, Some(3)]
.iter()
.filter_map(|x| *x)
.collect();
Flat Map
let nested = vec![vec![1, 2], vec![3, 4]];
let flat: Vec<i32> = nested
.iter()
.flat_map(|v| v.iter())
.collect();
Take and Skip
let first_three: Vec<i32> = vec![1, 2, 3, 4, 5]
.iter()
.take(3)
.collect();
let rest: Vec<i32> = vec![1, 2, 3, 4, 5]
.iter()
.skip(2)
.collect();
Zip
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
let zipped: Vec<(i32, i32)> = a.iter()
.zip(b.iter())
.map(|(x, y)| (*x, *y))
.collect();
Enumerate
let enumerated: Vec<(usize, i32)> = vec![10, 20, 30]
.iter()
.enumerate()
.map(|(i, x)| (i, *x))
.collect();
Chain
let chained: Vec<i32> = vec![1, 2].iter()
.chain(vec![3, 4].iter())
.collect();
Collecting Strategies
Vec
let vec: Vec<i32> = (0..10).collect();
HashMap
use std::collections::HashMap;
let map: HashMap<i32, i32> = vec![(1, 2), (3, 4)]
.into_iter()
.collect();
HashSet
use std::collections::HashSet;
let set: HashSet<i32> = vec![1, 2, 2, 3]
.into_iter()
.collect();
With Capacity
let mut vec = Vec::with_capacity(100);
vec.extend((0..100).map(|x| x * 2));
Lazy Evaluation
Iterators Are Lazy
let iterator = (0..1000)
.map(|x| x * 2)
.filter(|x| x % 3 == 0);
let doubled = iterator.clone();
let result: Vec<i32> = iterator.collect();
Early Termination
let result: Option<i32> = (0..100)
.map(|x| x * 2)
.find(|x| *x > 50);
Performance Considerations
Avoid Unnecessary Collects
let doubled: Vec<i32> = vec.iter().map(|x| x * 2).collect();
let filtered: Vec<i32> = doubled.iter().filter(|x| *x > 10).collect();
let result: Vec<i32> = vec.iter()
.map(|x| x * 2)
.filter(|x| *x > 10)
.collect();
Use Iterators Instead of Loops
let mut result = Vec::new();
for item in &vec {
if item % 2 == 0 {
result.push(item * 2);
}
}
let result: Vec<i32> = vec.iter()
.filter(|x| x % 2 == 0)
.map(|x| x * 2)
.collect();
Pre-allocate When Size Known
let mut result = Vec::with_capacity(vec.len());
result.extend(vec.iter().map(|x| x * 2));
Common Patterns
Sum and Product
let sum: i32 = vec.iter().sum();
let product: i32 = vec.iter().product();
Min and Max
let min = vec.iter().min();
let max = vec.iter().max();
Any and All
let has_positive = vec.iter().any(|x| *x > 0);
let all_positive = vec.iter().all(|x| *x > 0);
Fold
let sum = vec.iter().fold(0, |acc, x| acc + x);
Reduce
let max = vec.iter().reduce(|acc, x| if *x > acc { *x } else { acc });
Custom Iterators
Implementing Iterator Trait
struct Counter {
current: i32,
max: i32,
}
impl Iterator for Counter {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.max {
let value = self.current;
self.current += 1;
Some(value)
} else {
None
}
}
}
Using Custom Iterator
let counter = Counter { current: 0, max: 5 };
let values: Vec<i32> = counter.collect();
Important Rules
- Iterators are lazy: They don't execute until consumed
- Chain operations: Combine multiple adaptors in one chain
- Avoid unnecessary collects: Only collect when needed
- Use appropriate iterator:
iter(), iter_mut(), or into_iter()
- Pre-allocate when possible: Use
with_capacity() when size is known
- Prefer iterators over loops: More idiomatic and often faster
Examples from Project
Look for iterator usage in:
- Data processing pipelines
- Collection transformations
- Filtering and mapping operations
- Performance-critical sections
Common Patterns
✅ Good
let result: Vec<i32> = data.iter()
.filter(|x| x > 0)
.map(|x| x * 2)
.collect();
let found = data.iter().find(|x| *x > 100);
❌ Avoid
let step1: Vec<i32> = data.iter().map(|x| x * 2).collect();
let step2: Vec<i32> = step1.iter().filter(|x| *x > 10).collect();
for item in &data {
}