Why doesn't iterating require `mut` iterator?

The Iterator trait is defined as follows:

pub trait Iterator {
    // ...
    fn next(&mut self) -> Option<Self::Item>;
}

The next() method is declared mut self because advancing an iterator usually requires incrementing some internal state.

Strangely, the following code is allowed:

let v = vec![1, 2, 3];
let iter = v.iter(); // Note, `iter` is not declated as mutable!
for i in iter {
    println!("{}", i);
}

(Playground)

While a slightly modified, explicit version does not compile:

let v = vec![1, 2, 3];
let iter = v.iter();
loop {
    let i = if let Some(i) = iter.next() { i } else { break };
    println!("{}", i);
}
error[E0596]: cannot borrow `iter` as mutable, as it is not declared as mutable
 --> src/main.rs:5:34
  |
3 |     let iter = v.iter();
  |         ---- help: consider changing this to be mutable: `mut iter`
4 |     loop {
5 |         let i = if let Some(i) = iter.next() { i } else { break };
  |                                  ^^^^ cannot borrow as mutable

(Playground)

Why? I suspect it's not possible to change that now as this will break existing code, but is there any reason or is this a bug?

1 Like

The reason is that the for .. in .. syntax does not quite correspond to the explicit version you tried:

let v = vec![1, 2, 3];
let iter = v.iter();

// for i in iter { ... }
{
    let mut iter = iter.into_iter();
    while let Some(v) = iter.next() {
        // ...
    }
}

The IntoIterator part is also what allows you to do for i in vec![1, 2, 3] directly, without explicitly creating an iterator.

2 Likes

So it borrows it... Thanks.

Not quite. The IntoIterator (and thus the for loop) takes complete ownership of Self— You don’t have to mark the iterator/collection as mutable because it never appears modified within your code and becomes completely inaccessible after the loop body.

3 Likes

This is related to the fact that variables not declared mutable can become mutable when ownership is transferred. For example, this compiles:

fn takes_vec(mut v: Vec<u8>) {
    v.reverse();
    println!("{:?}", v);
}

fn main() {
    // v is not mutable
    let v = vec![1, 2, 3];
    takes_vec(v);
}
7 Likes

Another trick is that the thing you're iterating can be a reference, and then that is consumed by the loop instead of the container behind it. So for x in &v will call IntoIterator::into_iter(&v), which &Vec implements the same as v.iter(). This also works for &mut v and v.iter_mut().

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.