Iterators

Implementing Custom Iterators

To create a custom iterator in Rust, define a struct that holds the iteration state and implement std::iter::Iterator by specifying type Item and fn next(&mut self) -> Option<Self::Item>.

Step-by-Step Implementation of a Stateful Iterator

struct StepRange {
    current: i64,
    end: i64,
    step: i64,
}

impl StepRange {
    fn new(start: i64, end: i64, step: i64) -> Self {
        assert!(step > 0, "step must be positive");
        Self {
            current: start,
            end,
            step,
        }
    }
}

impl Iterator for StepRange {
    type Item = i64;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current >= self.end {
            return None;
        }
        let value = self.current;
        self.current += self.step;
        Some(value)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.current >= self.end {
            (0, Some(0))
        } else {
            let remaining = ((self.end - self.current + self.step - 1) / self.step) as usize;
            (remaining, Some(remaining))
        }
    }
}

impl ExactSizeIterator for StepRange {}

fn main() {
    let iter = StepRange::new(0, 15, 4);
    println!("Exact length: {}", iter.len());

    let collected: Vec<i64> = iter.collect();
    println!("Values:       {collected:?}");
}
Exact length: 4
Values:       [0, 4, 8, 12]

Implementing DoubleEndedIterator

If your custom iterator can also yield items from the back without colliding with the front cursor, implement DoubleEndedIterator by defining next_back(&mut self):

struct IndexWindow {
    front: usize,
    back: usize, // Exclusive upper bound
}

impl Iterator for IndexWindow {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        if self.front >= self.back {
            None
        } else {
            let idx = self.front;
            self.front += 1;
            Some(idx)
        }
    }
}

impl DoubleEndedIterator for IndexWindow {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.front >= self.back {
            None
        } else {
            self.back -= 1;
            Some(self.back)
        }
    }
}

fn main() {
    let mut win = IndexWindow { front: 10, back: 14 };
    println!("front: {:?}", win.next());
    println!("back:  {:?}", win.next_back());

    let rest_reversed: Vec<usize> = win.rev().collect();
    println!("rest (rev): {rest_reversed:?}");
}
front: Some(10)
back:  Some(13)
rest (rev): [12, 11]

Quick One-Off Iterators with std::iter::from_fn and successors

When you do not need a named iterator type in a public API, the standard library provides two generator functions in std::iter that build an Iterator directly from a closure:

  • std::iter::from_fn(f: impl FnMut() -> Option<T>): Calls the stateful closure on each .next() until it returns None.
  • std::iter::successors(first: Option<T>, succ: impl FnMut(&T) -> Option<T>): Generates each subsequent element from a reference to the previous element.