In Rust we often act upon iterators returned by the iter()
function. We can use for_each
to call code upon each element.
And with chain, we can elegantly combine two or more iterators. This lets us merge multiple loops into one, which can improve performance.
Here we introduce increment_if_four
—it receives a reference to a reference to string
data. It increments the count argument if the length is 4.
string
data (values) and call for_each
and increment_if_four
upon each element.chain()
to merge together two arrays of string
data. Then we call for_each
and increment_if_four
on these values.fn increment_if_four(value: &&str, count: &mut usize) { // Increment mutable argument if string length is 4. if value.len() == 4 { *count += 1; } } fn main() { // Part 1: Use for_each function on iter. let count = &mut 0; let values = ["", "1234"]; values.iter().for_each(|x| increment_if_four(x, count)); println!("INCREMENT_IF_FOUR = {count}"); // Part 2: Use for_each with chain. let values2 = ["bird", "", "dog"]; let values3 = ["red", "blue"]; values2 .iter() .chain(values3.iter()) .for_each(|x| increment_if_four(x, count)); println!("INCREMENT_IF_FOUR = {count}"); }INCREMENT_IF_FOUR = 1 INCREMENT_IF_FOUR = 3
With for_each
and chain we can combine two loops into one. Occasionally this can perform faster than two loops in Rust programs.
for
-loops to iterate over the 2 arrays. It checks the length of each string
.for_each
to combine the two loops into one. The counts are the same in both versions.for_each
to merge both loops is significantly faster.use std::time::*; fn increment_if_four(value: &&str, count: &mut usize) { if value.len() == 4 { *count += 1; } } fn main() { let values1 = ["bird", "", "dog"]; let values2 = ["red", "blue", "?"]; if let Ok(max) = "100000000".parse::<usize>() { let count1 = &mut 0; let count2 = &mut 0; // Version 1: use 2 for-loops. let t0 = Instant::now(); for _ in 0..max { for value in values1.iter() { increment_if_four(&value, count1); } for value in values2.iter() { increment_if_four(&value, count1); } } println!("{} ms", t0.elapsed().as_millis()); // Version 2: use chain with for_each. let t1 = Instant::now(); for _ in 0..max { values1 .iter() .chain(values2.iter()) .for_each(|x| increment_if_four(x, count2)); } println!("{} ms", t1.elapsed().as_millis()); println!("{count1} = {count2}"); } }476 ms for, for 16 ms chain, for_each 200000000 = 200000000
Suppose our Rust program has two collections (arrays or vectors), and we want to loop over both of them. With chain, we can just write one loop, with for_each
.
Chain and for_each
can often be used together. With for_each
, we can modify a mutable argument, but we cannot return a value. This is useful in some programs.