Iterators

Implementing IntoIterator

Implementing std::iter::IntoIterator on a custom collection enables it to be used directly in for loops and passed to generic functions bounded by IntoIterator.

Implementing IntoIterator for Owned (T) and Borrowed (&T, &mut T) Receivers

A complete collection typically provides up to three IntoIterator implementations:

Implementation Target Item Type IntoIter Type Purpose
impl<T> IntoIterator for MyCollection<T> T Owned iterator (or wrapped std::vec::IntoIter<T>) for x in collection
impl<'a, T> IntoIterator for &'a MyCollection<T> &'a T Borrowed iterator (or std::slice::Iter<'a, T>) for x in &collection
impl<'a, T> IntoIterator for &'a mut MyCollection<T> &'a mut T Mutable iterator (or std::slice::IterMut<'a, T>) for x in &mut collection

Delegating IntoIterator to an Inner Collection

When your custom collection wraps a standard container such as Vec<T>, you can reuse std::vec::IntoIter<T>, std::slice::Iter<'a, T>, and std::slice::IterMut<'a, T> as your IntoIter associated types without writing custom iterator state machines from scratch:

pub struct Playlist {
    tracks: Vec<String>,
}

impl Playlist {
    pub fn new(tracks: Vec<String>) -> Self {
        Self { tracks }
    }

    pub fn iter(&self) -> std::slice::Iter<'_, String> {
        self.tracks.iter()
    }

    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, String> {
        self.tracks.iter_mut()
    }
}

// 1. Owned iteration: `for track in playlist`
impl IntoIterator for Playlist {
    type Item = String;
    type IntoIter = std::vec::IntoIter<String>;

    fn into_iter(self) -> Self::IntoIter {
        self.tracks.into_iter()
    }
}

// 2. Shared reference iteration: `for track in &playlist`
impl<'a> IntoIterator for &'a Playlist {
    type Item = &'a String;
    type IntoIter = std::slice::Iter<'a, String>;

    fn into_iter(self) -> Self::IntoIter {
        self.tracks.iter()
    }
}

// 3. Mutable reference iteration: `for track in &mut playlist`
impl<'a> IntoIterator for &'a mut Playlist {
    type Item = &'a mut String;
    type IntoIter = std::slice::IterMut<'a, String>;

    fn into_iter(self) -> Self::IntoIter {
        self.tracks.iter_mut()
    }
}

fn main() {
    let mut list = Playlist::new(vec![
        String::from("Intro"),
        String::from("Main Theme"),
    ]);

    // Uses `impl IntoIterator for &mut Playlist`:
    for track in &mut list {
        track.push_str(" (Remastered)");
    }

    // Uses `impl IntoIterator for &Playlist`:
    for track in &list {
        println!("Borrowed: {track}");
    }

    // Uses `impl IntoIterator for Playlist` (consumes `list`):
    let owned: Vec<String> = list.into_iter().collect();
    println!("Collected owned: {owned:?}");
}
Borrowed: Intro (Remastered)
Borrowed: Main Theme (Remastered)
Collected owned: ["Intro (Remastered)", "Main Theme (Remastered)"]