Iterators
chain()
The .chain() adapter concatenates two iterators that yield the exact same Item type, exhausting the first iterator completely before pulling elements from the second iterator.
Signature
fn chain<U>(self, other: U) -> Chain<Self, U::IntoIter>
where
Self: Sized,
U: IntoIterator<Item = Self::Item>,
First: [ 1, 2 ] Second: [ 3, 4, 5 ]
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
Chain: [ 1, 2, 3, 4, 5 ]
Because other only needs to implement IntoIterator<Item = Self::Item>, the two iterators do not need to have the same concrete iterator type—for example, you can chain a std::slice::Iter with a std::iter::Once or a Map adapter, as long as both yield the same Item type.
Concatenating Slices, Prefix/Suffix Items, and Ranges
use std::iter::once;
fn main() {
let header = once("BEGIN");
let body = ["line-1", "line-2"];
let footer = once("END");
// Concatenates all three without allocating intermediate Vectors:
let packet: Vec<&str> = header.chain(body).chain(footer).collect();
println!("{packet:?}");
}
["BEGIN", "line-1", "line-2", "END"]
Conditionally Chaining an Optional Element
Because Option<T> implements IntoIterator<Item = T>, passing an Option<T> directly to .chain(opt) appends the item if Some(x) and appends nothing if None:
fn build_args(base: &[&str], verbose: bool) -> Vec<&str> {
let extra: Option<&str> = if verbose { Some("--verbose") } else { None };
base.iter().copied().chain(extra).collect()
}
fn main() {
println!("Quiet: {:?}", build_args(&["build", "--release"], false));
println!("Verbose: {:?}", build_args(&["build", "--release"], true));
}
Quiet: ["build", "--release"]
Verbose: ["build", "--release", "--verbose"]