The Iterator Trait
Iterator trait is the recipe every list-walker in Rust follows: it just needs to know how to hand back the next item.In this page:
Calling next Manually
Every iterator provides a next() method returning Some(item) while there are more elements, and None once exhausted. A for loop is just repeatedly calling next() under the hood.
Example: Calling next Manually
fn main() {
let mut iter = vec![1, 2, 3].into_iter();
println!("{:?}", iter.next());
println!("{:?}", iter.next());
println!("{:?}", iter.next());
println!("{:?}", iter.next());
}
Login to try C/C++/Java/PHP code in the editor
Implementing a Custom Iterator
Implementing Iterator for your own type only requires defining next(); the associated Item type declares what kind of value the iterator produces.
Example: Implementing a Custom Iterator
struct Countdown(u32);
impl Iterator for Countdown {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.0 == 0 {
None
} else {
self.0 -= 1;
Some(self.0 + 1)
}
}
}
fn main() {
let countdown = Countdown(3);
for n in countdown {
println!("{}", n);
}
}
Login to try C/C++/Java/PHP code in the editor
Free Adapter Methods from Iterator
Once a type implements Iterator by defining next(), it automatically gains access to many built-in adapter methods, such as .sum(), without any extra work.
Example: Free Adapter Methods from Iterator
struct Countdown(u32);
impl Iterator for Countdown {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.0 == 0 {
None
} else {
self.0 -= 1;
Some(self.0 + 1)
}
}
}
fn main() {
let total: u32 = Countdown(4).sum();
println!("Sum: {}", total);
}
Login to try C/C++/Java/PHP code in the editor
Iterators Are Lazy
Iterator adapters like .map() do not run their closure immediately -- they build a pipeline description that only executes once something consumes the iterator, such as .collect() or a for loop.
Example: Iterators Are Lazy
fn main() {
let numbers = vec![1, 2, 3];
let lazy_iter = numbers.iter().map(|n| {
println!("Processing {}", n);
n * 2
});
let result: Vec<i32> = lazy_iter.collect();
println!("{:?}", result);
}
Login to try C/C++/Java/PHP code in the editor
- Forgetting
.next()returns anOption<Item>, usingNoneto signal the iterator is exhausted. - Assuming iterators are eager -- most iterator adapters like
.map()are lazy and don't run until consumed. - Implementing
Iteratorbut forgetting it only requires definingnext(); every other method has a default implementation built on top of it.
- The
Iteratortrait requires just one method,next(&mut self) -> Option<Self::Item>. - Calling
.next()repeatedly yieldsSome(item)until the sequence is exhausted, then returnsNone. - Implementing
Iteratorfor a custom type automatically unlocks dozens of adapter methods like.map()and.filter(). - Iterators are lazy: adapters build up a pipeline that only actually runs when consumed, such as by
.collect()or aforloop.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: