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

Building Custom Iterators

You can design your own kind of list-walker for your own data, teaching it exactly how to hand out items one at a time.
Syntax
rust
struct Name {
    state: Type,
}

impl Iterator for Name {
    type Item = Type;
    fn next(&mut self) -> Option<Type> {
        // return Some(value) or None
    }
}

A Custom Iterator Struct

A custom iterator is typically a small struct holding whatever state is needed to compute the next item, with Iterator implemented on top of it.

Example: A Custom Iterator Struct

markup
// Define a struct `Evens` to group related fields together
struct Evens {
    current: i32,
    max: i32,
}

// Implement the `Iterator` trait for `Evens`
impl Iterator for Evens {
    type Item = i32;
    // Define the function `next` taking `self` and returning a `Option<i32>`
    fn next(&mut self) -> Option<i32> {
        // Check whether `self.current > self.max`
        if self.current > self.max {
            None
        // Otherwise, run this branch
        } else {
            // Declare an immutable variable `value`, set to `self.current`
            let value = self.current;
            self.current += 2;
            Some(value)
        }
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `evens`, set to `Evens { current: 0, max: 8 }`
    let evens = Evens { current: 0, max: 8 };
    // Loop over `evens`, binding each item to `n`
    for n in evens {
        // Print "{}" to the console, substituting in `n` (with a trailing newline)
        println!("{}", n);
    }
}

Using Adapters on a Custom Iterator

Once Iterator is implemented, a custom type automatically supports the full range of adapter methods, letting you build pipelines just as you would on a built-in iterator.

Example: Using Adapters on a Custom Iterator

markup
// Define a struct `Evens` to group related fields together
struct Evens {
    current: i32,
    max: i32,
}

// Implement the `Iterator` trait for `Evens`
impl Iterator for Evens {
    type Item = i32;
    // Define the function `next` taking `self` and returning a `Option<i32>`
    fn next(&mut self) -> Option<i32> {
        // Check whether `self.current > self.max`
        if self.current > self.max {
            None
        // Otherwise, run this branch
        } else {
            // Declare an immutable variable `value`, set to `self.current`
            let value = self.current;
            self.current += 2;
            Some(value)
        }
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `total` (an integer), set to `Evens { current: 0, max: 10 }.map(|n| n * 2).sum()`
    let total: i32 = Evens { current: 0, max: 10 }.map(|n| n * 2).sum();
    // Print "Total: {}" to the console, substituting in `total` (with a trailing newline)
    println!("Total: {}", total);
}

Implementing IntoIterator for a Collection

Implementing IntoIterator for a custom collection struct allows it to be used directly with a for loop, delegating to an inner iterator type.

Example: Implementing IntoIterator for a Collection

markup
// Define a struct `Bag` to group related fields together
struct Bag {
    items: Vec<i32>,
}

// Implement the `IntoIterator` trait for `Bag`
impl IntoIterator for Bag {
    type Item = i32;
    type IntoIter = std::vec::IntoIter<i32>;
    // Define the function `into_iter` taking `self` and returning a `Self::IntoIter`
    fn into_iter(self) -> Self::IntoIter {
        self.items.into_iter()
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `bag`, set to `Bag { items: vec![10, 20, 30] }`
    let bag = Bag { items: vec![10, 20, 30] };
    // Loop over `bag`, binding each item to `item`
    for item in bag {
        // Print "{}" to the console, substituting in `item` (with a trailing newline)
        println!("{}", item);
    }
}

Ensuring the Iterator Terminates

A correctly implemented iterator must eventually return None; otherwise, any code that consumes it fully (like .collect() or .sum()) will loop forever.

Example: Ensuring the Iterator Terminates

markup
// Define a struct `Countdown` to group related fields together
struct Countdown(u32);

// Implement the `Iterator` trait for `Countdown`
impl Iterator for Countdown {
    type Item = u32;
    // Define the function `next` taking `self` and returning a `Option<u32>`
    fn next(&mut self) -> Option<u32> {
        // Check whether `self.0 == 0`
        if self.0 == 0 {
            None
        // Otherwise, run this branch
        } else {
            self.0 -= 1;
            Some(self.0 + 1)
        }
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `collected` (a `Vec<u32>`), set to `Countdown(5).collect()`
    let collected: Vec<u32> = Countdown(5).collect();
    // Print "{:?}" to the console, substituting in `collected` (with a trailing newline)
    println!("{:?}", collected);
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Forgetting to implement IntoIterator for a collection struct if you want it to work directly in a for loop.
  2. Writing next() in a way that never returns None, causing any consuming method like .collect() to loop forever.
  3. Reimplementing common adapter logic manually instead of just implementing Iterator once and reusing the built-in adapter methods.
Chapter Summary
  • Implementing Iterator for a custom struct requires defining type Item and the next() method.
  • Implementing IntoIterator lets a custom collection type be used directly in a for loop.
  • A well-behaved iterator must eventually return None from next(), or consumers like .collect() will loop forever.
  • Custom iterators automatically gain access to the full standard library of iterator adapter methods.
🔒

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.