Need help with iterators

Can someone explain to me why this code doesn't work?

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

for val in v1_iter {
    println!("Got: {}", val);
}

let total: i32 = v1_iter.sum();

The compiler says:
v1_iter moved due to this implicit call to .into_iter()
help: consider borrowing to avoid moving into the for loop: &v1_iter

For future reference, it’s extremely useful if you include the compiler error message (below) and/or a playground link of the code that’s causing you problems.


error[E0382]: use of moved value: `v1_iter`
   --> src/main.rs:9:22
    |
3   |     let v1_iter = v1.iter();
    |         ------- move occurs because `v1_iter` has type `std::slice::Iter<'_, i32>`, which does not implement the `Copy` trait
4   | 
5   |     for val in v1_iter {
    |                -------
    |                |
    |                `v1_iter` moved due to this implicit call to `.into_iter()`
    |                help: consider borrowing to avoid moving into the for loop: `&v1_iter`
...
9   |     let total: i32 = v1_iter.sum();
    |                      ^^^^^^^ value used here after move
    |
note: this function consumes the receiver `self` by taking ownership of it, which moves `v1_iter`

Iterators in Rust are one-shot: they will produce each value once and never again. Because if this, for loops take ownership of the iterator they’re walking— by the time the loop exits, the iterator is exhausted.

You’ll need to make a new iterator for the sum call:

let total: i32 = v1.iter().sum();
1 Like

Or you can use v1_iter.clone() for the first use in the loop.

2 Likes

Iterators are one-time-use only. They can only return next element, and after visiting all elements, they have nothing else to do, and are useless.

Instead of holding on to and trying to recycle a temporary iterator object, just make a new one. It doesn't cost anything to make an iterator.

Under the hood an iterator is a struct which contains a reference back to the original value (or takes ownership of that value) and a variable to keep track of how much iteration had happened so far. In this case, it's a usize that contains the index of the next element to return.

The Iterator trait just has a next() method that, in this case, gets the next element of the vec, increases the index by one, and returns the element.

So after the first time through the loop, even if you did still have access to the v1_iter value, it would already be exhausted (the index would point to the end of the vec), and .sum() wouldn't have anything left to sum.