Iterators are a powerful language feature in Rust, described by the Iterator trait. Iterators allow you to perform many operations on collection-like types, e.g. Vec<T>, and they are easily composable.

Adapters and Consumers

Iterator methods can be broken into two distinct groups:


Adapters take an iterator and return another iterator

//         Iterator  Adapter
//             |       |
let my_map = (1..6).map(|x| x * x);
println!("{:?}", my_map);
Map { iter: 1..6 }

Note that the values were not enumerated, which indicates that iterators are not eagerly evaluated — iterators are "lazy".


Consumers take an iterator and return something other than an iterator, consuming the iterator in the process.

//                    Iterator  Adapter       Consumer
//                        |       |              |
let my_squares: Vec<_> = (1..6).map(|x| x * x).collect();
println!("{:?}", my_squares);
[1, 4, 9, 16, 25]

Other examples of consumers include find, fold, and sum.

let my_squared_sum: u32 = (1..6).map(|x| x * x).sum();
println!("{:?}", my_squared_sum);

A short primality test

fn is_prime(n: u64) -> bool {
    (2..n).all(|divisor| n % divisor != 0)

Of course this is isn't a fast test. We can stop testing at the square root of n:

    .take_while(|divisor| divisor * divisor <= n)
    .all(|divisor| n % divisor != 0)

Custom iterator

struct Fibonacci(u64, u64);

impl Iterator for Fibonacci {
    type Item = u64;
    // The method that generates each item
    fn next(&mut self) -> Option<Self::Item> {
        let ret = self.0;
        self.0 = self.1;
        self.1 += ret;
        Some(ret) // since `None` is never returned, we have an infinite iterator

    // Implementing the `next()` method suffices since every other iterator
    // method has a default implementation

Example use:

// the iterator method `take()` is an adapter which limits the number of items
// generated by the original iterator
for i in Fibonacci(0, 1).take(10) {
    println!("{}", i);