Iterators
zip()
The .zip() adapter lock-steps two iterators in parallel, returning a std::iter::Zip<Self, U::IntoIter> iterator that yields pairs (Self::Item, U::Item) and stops as soon as either iterator returns None.
Signature
fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter>
where
Self: Sized,
U: IntoIterator,
Because other is bounded by U: IntoIterator, you can pass a slice, Vec, array, or range directly to .zip(other) without calling .into_iter() on other first.
Iter A: [ "x", "y", "z" ]
Iter B: [ 10, 20, 30, 40 ] (40 is never consumed)
│ │ │
▼ ▼ ▼
Zip: [ ("x", 10), ("y", 20), ("z", 30) ]
Pairing Keys and Values or Computing Element-Wise Operations
use std::collections::HashMap;
fn main() {
let keys = ["host", "port", "region"];
let values = ["localhost", "5432", "ap-south-1", "ignored_extra"];
// Stops after 3 pairs when `keys` is exhausted:
let config: HashMap<&str, &str> = keys.into_iter().zip(values).collect();
// Element-wise dot product of two vectors:
let a = [1_i32, 2, 3];
let b = [4_i32, 5, 6];
let dot_product: i32 = a.iter().zip(&b).map(|(x, y)| x * y).sum();
println!("Config count: {}", config.len());
println!("Dot product: {dot_product}");
}
Config count: 3
Dot product: 32
Reversing .zip() with .unzip()
The inverse consumer method .unzip() consumes an iterator of 2-tuples (A, B) and splits it into a pair of collections (FromA, FromB) in a single pass:
fn main() {
let pairs = [(1_u32, "one"), (2, "two"), (3, "three")];
let (numbers, words): (Vec<u32>, Vec<&str>) = pairs.into_iter().unzip();
println!("Numbers: {numbers:?}");
println!("Words: {words:?}");
}
Numbers: [1, 2, 3]
Words: ["one", "two", "three"]
Free Function std::iter::zip
The standard library also provides the free function std::iter::zip(a, b), which accepts two IntoIterator arguments symmetrically (for (x, y) in std::iter::zip(&xs, &ys)).