RustArena

Step 1 of 7

What an iterator is

An iterator is a value that hands out items one at a time. Every for loop you've written used one behind the scenes. In Rust, an iterator is any type that implements the Iterator trait, which has one required method:

trait Iterator {
    type Item;                                 // the type of the items it produces
    fn next(&mut self) -> Option<Self::Item>;  // the next item, or None when finished
}

type Item is an associated type: each iterator says what kind of item it yields. (You'll implement this trait yourself in the last step.) Here is next called by hand:

fn main() {
    let scores = vec![30, 85, 60];
    let mut it = scores.iter();
    println!("{:?}", it.next());
    println!("{:?}", it.next());
    println!("{:?}", it.next());
    println!("{:?}", it.next());
}
Some(30)
Some(85)
Some(60)
None

What a for loop really does

This loop:

for s in &scores {
    println!("{s}");
}

is shorthand for:

let mut it = (&scores).into_iter();
while let Some(s) = it.next() {
    println!("{s}");
}

for calls into_iter() on whatever you give it, then calls next() until it gets None. That's why you can loop over vectors, arrays, ranges, .chars(), .lines(), maps and sets: they all turn into iterators.

Three ways to iterate a collection

Call Items The collection afterwards Same as
v.iter() &T (look) unchanged for x in &v
v.iter_mut() &mut T (change in place) changed for x in &mut v
v.into_iter() T (owned values) gone: moved into the loop for x in v
fn main() {
    let mut prices = vec![10, 20, 30];
    for p in prices.iter_mut() {
        *p += 1; // change each price in place
    }
    for p in prices.iter() {
        print!("{p} ");
    }
    println!();

    let names = vec![String::from("ann"), String::from("bo")];
    for name in names.into_iter() {
        let owned: String = name; // each String is ours now
        println!("{}", owned.to_uppercase());
    }
}
11 21 31
ANN
BO

Common mistakes

fn main() {
    let v = vec![1, 2, 3];
    let it = v.iter();
    println!("{:?}", it.next());
}
error[E0596]: cannot borrow `it` as mutable, as it is not declared as mutable
fn main() {
    let names = vec![String::from("Ann"), String::from("Bo")];
    for n in names.into_iter() {
        println!("{n}");
    }
    println!("{}", names.len());
}
error[E0382]: borrow of moved value: `names`

Use .iter() (or for n in &names) when you still need the collection afterwards.

Your task

Fill in the blanks: create an iterator over tasks and take its first item with the method that advances an iterator, so the program prints:

Some("write")
Some("test")
Some("ship")
None

Challenge 2

Write fn apply_raise(salaries: &mut [u32], percent: u32) that gives every salary a raise of percent percent, in place, using iter_mut(). Use integer math: the raise for a salary s is s * percent / 100. For example, [1000, 2500] with 10 becomes [1100, 2750].

Challenge 3

An iterator remembers where it stopped. Using one iterator it over lines, call next() once to take the header line and print it as header: .... Then loop over the same iterator with for line in it to print the remaining lines as row: ...:

header: name,score
row: ann,90
row: bo,75

Next: From loops to iterator chains