---
title: "19.3 The Iterator trait"
description: "What an iterator really is: the next method, the Item associated type, the iter/iter_mut/into_iter trio, and why iterators are lazy."
url: "https://learnrust.net/chapter-19/the-iterator-trait/"
last_updated: "2026-06-13"
---

# 19.3 The Iterator trait

You've been iterating since chapter 7. `for x in &scores` walks a vector; `for c in word.chars()` walks the characters of a string. Underneath every one of those loops is a single small trait, and once you see it, a huge amount of the standard library stops being magic. An **iterator** is any value that knows how to produce a sequence of items, one at a time, on request. That's the entire idea. The trait that captures it is `Iterator`, and it has essentially one required method.

## The trait itself

Stripped to its core, `Iterator` looks like this:

```rust
trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
}
```

Two pieces. `type Item` is an **associated type**: a type that belongs to the trait and that each implementor fills in, naming the kind of thing this particular iterator yields (`i32`, `&String`, `char`). It's written `type Item;` in the trait and `type Item = i32;` in an implementation, and you read `Self::Item` as "whatever this iterator decided to yield." And `next` is the engine: call it, and it returns `Some(item)` with the next value, or `None` once the sequence is exhausted. The `Option` return (chapter 11) *is* how an iterator says "I'm done", there's no separate "are we finished?" call, the `None` is the signal.

Because `next` takes `&mut self`, calling it changes the iterator: it advances. An iterator is a stateful little machine that remembers where it is. Let's watch one run by hand:

```rust
fn main() {
    let v = vec![10, 20, 30];
    let mut it = v.iter();

    println!("{:?}", it.next());
    println!("{:?}", it.next());
    println!("{:?}", it.next());
    println!("{:?}", it.next());
}
```

```
Some(10)
Some(20)
Some(30)
None
```

`v.iter()` builds an iterator over the vector; `it` must be `mut` because each `next` mutates its internal position. Three `Some`s, then `None` forever after. A `for` loop is exactly this: call `next` in a loop, bind each `Some` value to the loop variable, stop at the first `None`. We'll prove that claim properly in lesson [19.6](https://learnrust.net/chapter-19/for-loops-demystified/); for now, know that the loops you've written were calling `next` all along.

## Three ways to iterate a collection

That little program called `v.iter()`. There are three sibling methods, and the difference between them is, once again, just chapter 8 and 9 ownership applied to iteration. Each produces items of a different type:

`iter()` yields **shared references** `&T`. The collection is borrowed; you can read each element but not change it, and the collection is still yours afterward.

`iter_mut()` yields **mutable references** `&mut T`. The collection is mutably borrowed; you can change each element in place.

`into_iter()` yields **owned values** `T`. The collection is *consumed* (moved into the iterator); you get each element by value, and the original is gone.

Here are all three:

```rust
fn main() {
    let v = vec![1, 2, 3];
    let total: i32 = v.iter().sum();      // &i32 each; v still usable
    println!("sum is {total}, v is {v:?}");

    let mut v2 = vec![1, 2, 3];
    for n in v2.iter_mut() {              // &mut i32 each
        *n *= 10;
    }
    println!("{v2:?}");

    let v3 = vec![String::from("a"), String::from("b")];
    for s in v3.into_iter() {            // String each, by value; v3 consumed
        println!("owning {s}");
    }
    // v3 is gone here.
}
```

```
sum is 6, v is [1, 2, 3]
[10, 20, 30]
owning a
owning b
```

This is why `for x in &v` and `for x in v` behave differently, and you've felt it without naming it. `&v` calls `iter()` (borrow, `x` is `&T`), `&mut v` calls `iter_mut()`, and a bare `v` calls `into_iter()` (consume, `x` is `T`). Choosing the loop header chooses the ownership mode. The owned form is the one you want when you need to *take* the elements out, for example to move each `String` somewhere else; the borrowing forms are the everyday default.

> **Key insight**
>
> `iter` / `iter_mut` / `into_iter` are the iteration version of `&` / `&mut` / owned. Whenever you reach for an iterator, the first decision is the same one you make for any value: do I need to *read* the elements, *modify* them in place, or *take ownership* of them? That answer picks the method, and everything downstream, what the loop variable's type is, whether the collection survives, follows from it.

## Iterators are lazy

Here is the single most important fact about iterators, and the one beginners trip on. An iterator does *nothing* until something asks it for values. Building one is free and instant; it just sets up the machine. Look:

```rust
fn main() {
    let v = vec![1, 2, 3];
    let doubler = v.iter().map(|x| {
        println!("doubling {x}");
        x * 2
    });

    println!("iterator built, nothing has happened yet");
}
```

```
iterator built, nothing has happened yet
```

The `map` closure, which prints "doubling", *never runs*. `map` (the subject of the next lesson) doesn't double anything; it builds a new iterator that *will* double, when asked. Nothing asks here, so nothing happens. This is called **laziness**, and it's deliberate: it lets you chain many transformations together with no wasted work, because each value flows through the whole chain only when it's finally pulled out the end.

What pulls values out? A `for` loop does, or a method that consumes the iterator, like `sum`, `count`, or `collect` (lesson [19.5](https://learnrust.net/chapter-19/consuming-iterators/)). Add one and the work happens:

```rust
fn main() {
    let v = vec![1, 2, 3];
    let doubled: Vec<i32> = v.iter().map(|x| {
        println!("doubling {x}");
        x * 2
    }).collect();

    println!("{doubled:?}");
}
```

```
doubling 1
doubling 2
doubling 3
[2, 4, 6]
```

Now `collect` drives the iterator, repeatedly calling `next`, which pulls each value through `map`, which runs the closure. Laziness is why "build a pipeline, then run it once at the end" is the natural shape of iterator code, and why an iterator with no consumer is almost always a bug the compiler will warn you about (`unused must-use` on the iterator).

> **A built-but-unconsumed iterator does nothing**
>
> `v.iter().map(|x| do_something(x));` with no consumer at the end runs `do_something` zero times. New Rust programmers write this expecting a side effect and get silence. If you want to run a closure for its effect over every element and don't need a result, either use a `for` loop (clearer for side effects) or end the chain with `.for_each(...)`. A lone adapter chain that you drop on the floor is dead code, and the compiler warns you so.

## Quiz time

**Question #1**

What is the one required method of the `Iterator` trait, and how does an iterator signal that it's finished?

<details class="solution">
<summary>Show solution</summary>

The required method is `next(&mut self) -> Option<Self::Item>`. It returns `Some(item)` for each value in turn and `None` once the sequence is exhausted. The `None` *is* the "finished" signal; there's no separate query. `Item` is an associated type naming what the iterator yields. (`next` takes `&mut self` because advancing changes the iterator's internal position.)

</details>

**Question #2**

You have `let v = vec![String::from("a"), String::from("b")]`. What's the difference between `v.iter()`, `v.iter_mut()`, and `v.into_iter()`?

<details class="solution">
<summary>Show solution</summary>

`v.iter()` yields `&String` (shared borrow, read-only, `v` survives). `v.iter_mut()` yields `&mut String` (mutable borrow, lets you change elements in place, `v` survives). `v.into_iter()` yields `String` by value (consumes `v`, moving each element out; `v` is gone afterward). They're the `&` / `&mut` / owned distinction from chapters 8 and 9, applied to iteration.

</details>

**Question #3**

What does this print, and why?

```rust
let nums = vec![1, 2, 3];
nums.iter().map(|x| println!("{x}"));
println!("done");
```

<details class="solution">
<summary>Show solution</summary>

It prints just `done`. The `map` builds a lazy iterator but nothing consumes it, so the closure never runs and none of the numbers print. (The compiler also warns that the iterator is unused.) To actually print each number, use a `for` loop or end with `.for_each(|x| println!("{x}"))`.

</details>

You now know what an iterator *is* and that it does nothing until driven. The next lesson ([19.4](https://learnrust.net/chapter-19/iterator-adapters/)) is the fun part: the **adapters** like `map`, `filter`, and `zip` that transform one iterator into another, building the pipelines laziness was designed for.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
