In Rust programs, like programs in any language, we often need to loop or iterate over elements. Iter()
is a helpful function that is used in for
-loops in Rust.
By returning references, iter()
protects the elements of the loop from being modified. This makes code more reliable as the loop will not fail in a mysterious way.
Here we have a vector of 3 color strings. We then use a for
-loop over the colors—we call iter()
in the for
-loop statement.
fn main() { let colors = vec!["blue", "orange", "yellow"]; // Use iter over the vector. for color in colors.iter() { println!("{}", color); } }blue orange yellow
The iter()
function returns an immutable reference to each element looped over. This means we cannot mutate the value behind the reference.
fn main() { let colors = vec!["blue", "orange", "yellow"]; // Iter returns immutable references so the elements cannot be changed. for color in colors.iter() { *color = "grey"; } }error[E0594]: cannot assign to `*color`, which is behind a `&` reference
Iter_mut
Suppose we have an array or vector and want to change elements in it as we loop over them. The iter_mut
function is helpful here as it returns mutable references.
fn main() { let mut values = [0; 10]; // Set all elements in the array to 3. for value in values.iter_mut() { // Dereference and assign. *value = 3; } println!("{:?}", values); }[3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
Into_iter
It is sometimes useful to call the into_iter
function. With into_iter
can avoid having references to elements in return values.
Into_iter
is often needed when using collect()
to create a vector of the original element type.fn main() { let values = vec![1, 2, 3]; // Use into_iter to avoid references to elements and have usize elements. let result = values.into_iter().collect::<Vec<usize>>(); println!("{:?}", result); }[1, 2, 3]
Once we call iter()
on a vector or array, we can access the iterator methods. One common method to call is enumerate.
Enumerate()
returns the index and value for each element in an iterator.fn main() { let colors = vec!["blue", "yellow", "green"]; // Use enumerate on iter() to access values and their indexes. for (i, color) in colors.iter().enumerate() { println!("{i} {color}"); } }0 blue 1 yellow 2 green
With iter()
and zip, we can loop over two vectors or arrays at once. The elements are returned as tuples (pairs). This can improve some loops that use iterators.
fn main() { let left = vec![1, 2, 3]; let right = vec![4, 5, 6]; // Use iter and zip to loop over both vectors at once. for pair in left.iter().zip(right) { println!("ZIP: {} {}", pair.0, pair.1); } }ZIP: 1 4 ZIP: 2 5 ZIP: 3 6
Min
and maxIt is possible to use min()
and max()
on an iterator to get the smallest or largest values. An option is returned, so we must use unwrap
or an if-let
Some statement.
min()
or max after calling iter()
we will get a reference to the value. Using into_iter
will give us values, not references.fn main() { let values = [10, 5, 3, 20, 4]; // Use min and unwrap. let min = values.into_iter().min().unwrap(); // Use max. let max = values.into_iter().max().unwrap(); println!("MIN = {min}, MAX = {max}"); }MIN = 3, MAX = 20
Is there any performance loss when using iter
instead of a for range loop? In this benchmark we try to answer this question.
for-range
loop over the indexes of the vector. We add up all the values in the vector repeatedly.iter()
function to access each element.iter
. Iter()
is a zero-cost abstraction in Rust.use std::time::*; fn main() { let values = vec![1; 100000]; if let Ok(max) = "100000".parse::<usize>() { let mut count = 0; // Version 1: use range loop. let t0 = Instant::now(); for _ in 0..max { for i in 0..values.len() { count += values[i]; } } println!("{} ms", t0.elapsed().as_millis()); // Version 2: use iter. let t1 = Instant::now(); for _ in 0..max { for value in values.iter() { count += value; } } println!("{} ms", t1.elapsed().as_millis()); println!("{}", count); } }839 ms 838 ms -1474836480
Using iter()
and iter_mut()
is often done in Rust programs. It can improve code reliability, as it will avoid programming bugs where values are modified in unexpected ways during looping.