Rust Iterators
An iterator is a value that hands out items one at a time. It hands out an item only when asked.
next() hands over one item at a time
An iterator is any type with a next() method. It gives Some(item), or, at the end, None:
let mut it = vec![10, 20].into_iter();
println!("{:?} {:?} {:?}", it.next(), it.next(), it.next());iter() borrows the items
Use vec.iter() to borrow items as &T — the list stays yours:
let names = vec!["alan", "ada"];
for name in names.iter() { println!("{}", name); }
println!("still owned: {:?}", names);into_iter() takes the items
Use vec.into_iter() to take items as T. The list is used up — names cannot be used after this loop:
let names = vec!["ada", "grace"];
for name in names.into_iter() { println!("{}", name); }iter_mut() changes items in place
Use vec.iter_mut() to borrow items as &mut T, so you can change them where they sit:
let mut scores = vec![1, 2, 3];
for s in scores.iter_mut() { *s *= 10; }
println!("{:?}", scores);Iterators are lazy
Building a chain of steps does no work by itself. Work happens only when something pulls — here, one call to next(). Watch when the doubling line prints:
let mut steps = vec![1, 2, 3].into_iter().map(|n| { println!("doubling {}", n); n * 2 });
println!("built, nothing ran yet");
println!("first = {:?}", steps.next());Ready-made tools ride along
Any iterator gains many ready-made tools: enumerate, zip, chain, skip, take, and more. Two of them pick a slice out of the middle here:
let picked: Vec<i32> = vec![1, 2, 3, 4, 5].into_iter().skip(1).take(2).collect();
println!("{:?}", picked);Example
fn main() {
let names = vec!["ada", "grace", "edsger"];
for (i, name) in names.iter().enumerate() {
println!("{}: {}", i + 1, name);
}
println!("still owned: {:?}", names);
}Key points
- The trait behind into_iter has a name: IntoIterator.
- You can implement it for your own types.
In this example, names is a Vec of three names. .iter() borrows them one by one. .enumerate() pairs each borrowed name with its position, starting at 0. The loop adds 1 to the position for display and prints 1: ada, 2: grace, 3: edsger. Because .iter() only borrowed the names, names is still fully owned afterwards — the last println! prints the whole list to prove it. The Rust IntoIterator lesson shows how to implement IntoIterator for your own types.
Note
A for loop is just friendly spelling over an iterator — for x in list uses into_iter() under the hood.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
When does the code inside an iterator chain actually run?