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"]