Nugget 14

Home

IntoIterator: The for Loop Interface

You write for x in vec and it works. But for x in &vec also works. And for x in &mut vec works too. How does one syntax produce three different behaviors? Meet IntoIterator.

The IntoIterator Trait

This is the trait that powers every for loop:

trait IntoIterator {
    type Item;
    type IntoIter: Iterator<Item = Self::Item>;

    fn into_iter(self) -> Self::IntoIter;
}

A type implements IntoIterator if it can be turned into an iterator. The for loop is just sugar for:

// What you write:
for item in collection {
    // ...
}

// What the compiler generates:
let mut iter = collection.into_iter();
while let Some(item) = iter.next() {
    // ...
}

The key: it calls collection.into_iter(). So the behavior depends entirely on which implementation of IntoIterator is used.

One Collection, Three Behaviors

Vec<T> doesn't implement IntoIterator once. It implements it three times — for Vec<T>, &Vec<T>, and &mut Vec<T>:

// 1. for x in vec — consumes the Vec
impl<T> IntoIterator for Vec<T> {
    type Item = T;
    type IntoIter = IntoIter<T>;
    fn into_iter(self) -> IntoIter<T> { /* ... */ }
}

// 2. for x in &vec — borrows immutably
impl<'a, T> IntoIterator for &'a Vec<T> {
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;
    fn into_iter(self) -> Iter<'a, T> { /* ... */ }
}

// 3. for x in &mut vec — borrows mutably
impl<'a, T> IntoIterator for &'a mut Vec<T> {
    type Item = &'a mut T;
    type IntoIter = IterMut<'a, T>;
    fn into_iter(self) -> IterMut<'a, T> { /* ... */ }
}

That's why for x in &vec gives you &T items without consuming vec — it's calling IntoIterator for &Vec<T>, not Vec<T>.

So for calls .into_iter()

This means for x in &vec is equivalent to for x in vec.iter(). Both ultimately call .next() on the same kind of iterator:

let v = vec![1, 2, 3];

// These are exactly equivalent:
for x in &v { println!("{x}"); }
for x in v.iter() { println!("{x}"); }

// And these are equivalent too:
for x in v {}  // consumes v
for x in v.into_iter() {}  // also consumes v

Making Your Own Type Iterable

Here's how to implement IntoIterator for a custom collection:

struct MyList {
    items: Vec<String>,
}

// Consuming iterator
impl IntoIterator for MyList {
    type Item = String;
    type IntoIter = std::vec::IntoIter<String>;

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

// Borrowing iterator
impl<'a> IntoIterator for &'a MyList {
    type Item = &'a String;
    type IntoIter = std::slice::Iter<'a, String>;

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

// Now you can write:
let list = MyList { items: vec!["a".into(), "b".into()] };

for item in &list {      // borrows
    println!("{item}");
}

for item in list {         // consumes
    println!("{item}");
}
// list is gone now

The Bigger Picture

IntoIterator explains why everything works with for:

Type for x in type Item type
Vec<T> for x in vec T (consumes)
&Vec<T> for x in &vec &T
&mut Vec<T> for x in &mut vec &mut T
[T; N] (array) for x in &arr &T
Range<T> for x in 0..5 T
HashMap<K, V> for x in &map (&K, &V)
Option<T> for x in opt T (0 or 1 items)

Everything that works with for implements IntoIterator. It's a single trait that unifies all iteration.

Key Takeaways