🎓 A1Learner
🔍

Rust IntoIterator

IntoIterator is the trait that lets a value be walked item by item. The into_iter method comes from this trait.

for is into_iter in disguise

Every for loop calls into_iter() on the value, then pulls next() again and again until None:

let names = vec!["ada", "grace"];
for name in names {
    println!("{name}");
}

The same walk, written out

IntoIterator is the trait with one method: into_iter(self). It hands over an iterator — and takes the value by value, so the original is used up:

let numbers = [10, 20, 30];
let mut it = numbers.into_iter();
println!("{:?} {:?}", it.next(), it.next());

Implement it for your own type

Set type Item to what comes out, and type IntoIter to the iterator type you hand over. The easiest honest implementation stores a Vec inside your type and returns that Vec's own iterator:

impl IntoIterator for Team {
    type Item = String;
    type IntoIter = std::vec::IntoIter<String>;
    fn into_iter(self) -> Self::IntoIter {
        self.members.into_iter()
    }
}

Then for just works

That one impl is all a for loop needs:

let team = Team {
    members: vec![String::from("ada"), String::from("grace")],
};
for member in team {
    println!("member = {member}");
}

Example

use std::vec;

struct Team {
    members: Vec<String>,
}

impl IntoIterator for Team {
    type Item = String;
    type IntoIter = vec::IntoIter<String>;

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

fn main() {
    let team = Team {
        members: vec![String::from("ada"), String::from("grace")],
    };
    for member in team {
        println!("member = {member}");
    }
    let numbers = [10, 20, 30];
    let doubled: Vec<i32> = numbers.into_iter().map(|n| n * 2).collect();
    println!("doubled = {:?}", doubled);
}

Key points

  • Vec, arrays, ranges, maps and sets all implement IntoIterator — that is why for works on all of them
  • iter() and iter_mut() are not part of the trait.
  • They are ordinary extra methods on collections.
  • Use them when you want to borrow instead of take.
  • Loop over &collection or .iter() when the collection must survive.

In this example, Team is a struct holding one Vec of names. Its IntoIterator impl says Item is String. It says IntoIter is the Vec's own iterator type. And into_iter simply hands over that iterator. That one impl is enough. The for loop walks the team. It prints member = ada and member = grace. The team is used up by the loop, exactly like a Vec would be. The last lines show the same trait at work in the standard library. An array's into_iter feeds map and collect. Together they build doubled = [20, 40, 60].

Note

Because into_iter takes self, looping over a collection with for uses it up, just like calling .into_iter() yourself.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

What does for x in thing do under the hood?