Iterators
collect()
The .collect() consumer drives an iterator to completion and gathers its elements into any target type B that implements the FromIterator<Self::Item> trait.
Signature and Type Inference
fn collect<B: FromIterator<Self::Item>>(self) -> B
where
Self: Sized,
Because .collect() is generic over its return type B, the compiler almost always needs either a type annotation on the variable or turbofish syntax (.collect::<B>()) to know which FromIterator implementation to invoke. You can use _ inside the container type (Vec<_>, HashMap<_, _>) to let the compiler infer the element types:
use std::collections::{BTreeSet, HashMap};
fn main() {
// 1. Variable type annotation with inferred element type `Vec<_>`:
let squares: Vec<_> = (1..=4).map(|x| x * x).collect();
// 2. Turbofish syntax `.collect::<BTreeSet<_>>()`:
let unique = [3, 1, 2, 3, 1].into_iter().collect::<BTreeSet<_>>();
// 3. Collecting `(K, V)` tuples into a `HashMap`:
let pairs = [("http", 80_u16), ("https", 443)];
let map: HashMap<_, _> = pairs.into_iter().collect();
println!("Vec: {squares:?}");
println!("BTreeSet: {unique:?}");
println!("HashMap: {map:?}");
}
Vec: [1, 4, 9, 16]
BTreeSet: {1, 2, 3}
HashMap: {"http": 80, "https": 443}
Non-Collection FromIterator Targets (String and Result)
FromIterator is implemented for several types beyond standard collection containers:
Target Type B |
Required Iterator::Item |
Behavior of .collect::<B>() |
|---|---|---|
Vec<T>, VecDeque<T>, HashSet<T> |
T |
Builds container from yielded items |
HashMap<K, V>, BTreeMap<K, V> |
(K, V) |
Inserts each key-value tuple |
String |
char, &char, &str, String, Cow<'_, str> |
Concatenates characters or string slices into a single String |
Result<C, E> (where C: FromIterator<T>) |
Result<T, E> |
Short-circuits on the first Err(e); otherwise returns Ok(C) |
Option<C> (where C: FromIterator<T>) |
Option<T> |
Short-circuits on the first None; otherwise returns Some(C) |
Short-Circuiting Iterator<Item = Result<T, E>> into Result<Vec<T>, E>
Collecting an iterator of Result<T, E> into Result<Vec<T>, E> stops polling the iterator at the first Err(e) without evaluating remaining elements:
fn parse_all(inputs: &[&str]) -> Result<Vec<i32>, std::num::ParseIntError> {
inputs.iter().map(|s| s.parse::<i32>()).collect()
}
fn main() {
println!("All valid: {:?}", parse_all(&["10", "20", "30"]));
println!("Has error: {:?}", parse_all(&["10", "oops", "30"]));
}
All valid: Ok([10, 20, 30])
Has error: Err(ParseIntError { kind: InvalidDigit })