RustArena

Iterating over collections in Rust: iter, iter_mut and into_iter

The three ways to loop over a Vec, array or HashMap in Rust: &v (iter), &mut v (iter_mut) and v (into_iter), plus enumerate, zip and rev.

There are three ways to loop over a collection, and they differ in what you get for each element and what happens to the collection:

Loop Same as Each item is Collection afterwards
for x in &v v.iter() &T (shared borrow) unchanged, still usable
for x in &mut v v.iter_mut() &mut T (can modify) modified, still usable
for x in v v.into_iter() T (owned) moved: gone
fn main() {
    let mut prices = vec![100, 250, 40];

    for p in &prices {
        print!("{p} ");
    }
    println!();

    for p in &mut prices {
        *p += 5;
    }
    println!("{prices:?}");

    for p in prices {
        print!("{} ", p * 2);
    }
    println!();
}
100 250 40
[105, 255, 45]
210 510 90

Use &v by default. Use &mut v to change elements in place (with *x to reach the value). Use v when you're done with the collection and want to move its elements somewhere else, like into another collection or a thread.

Index and value together: enumerate

Instead of for i in 0..v.len() with v[i], write for (i, x) in v.iter().enumerate(). It's clearer, can't go out of bounds, and clippy suggests it (needless_range_loop). Other everyday adapters:

Maps and sets

Iterating a HashMap gives (&K, &V) tuples: for (name, score) in &scores. Use .keys() or .values() for one side, .values_mut() to change values. The order is unspecified, so sort the entries (or use BTreeMap) before printing.

Arrays and strings

Arrays work like vectors: for x in [1, 2, 3] takes items by value (since the 2021 edition), for x in &arr borrows. A String isn't directly iterable: choose .chars() (characters), .bytes(), .lines() or .split_whitespace().

Common mistakes

fn main() {
    let mut v = vec![1, 2, 3];
    for x in &mut v {
        x += 1;
    }
    println!("{v:?}");
}
error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut {integer}`

Write *x += 1.

Example

use std::collections::HashMap;

fn main() {
    let names = vec!["Ferris", "Corro", "Gopher"];
    let mut scores = vec![72, 95, 88];

    for (i, name) in names.iter().enumerate() {
        println!("{}. {name}", i + 1);
    }

    for s in &mut scores {
        *s += 5;
    }

    for (name, score) in names.iter().zip(&scores) {
        println!("{name}: {score}");
    }

    for pair in scores.windows(2) {
        println!("change {:+}", pair[1] - pair[0]);
    }

    let mut by_name: HashMap<&str, i32> = HashMap::new();
    for (name, score) in names.iter().zip(scores.iter()) {
        by_name.insert(name, *score);
    }
    let mut keys: Vec<_> = by_name.keys().collect();
    keys.sort();
    for k in keys {
        println!("{k} -> {}", by_name[k]);
    }

    let total: i32 = scores.into_iter().sum(); // consumes scores
    println!("total {total}");
}

Output:

1. Ferris
2. Corro
3. Gopher
Ferris: 77
Corro: 100
Gopher: 93
change +23
change -7
Corro -> 100
Ferris -> 77
Gopher -> 93
total 270

Practice it