Collecting Option Values
When an iterator yields Option<T> values, Rust provides two distinct ways to gather them into a collection depending on whether a None element should abort the entire operation (Option<Vec<T>>) or be silently skipped (Vec<T>).
Comparing the Two Collection Strategies for Iterator<Item = Option<T>>
| Strategy | Idiom | Result on [Some(1), Some(2)] |
Result on [Some(1), None, Some(3)] |
|---|---|---|---|
| 1. All-or-Nothing (Short-Circuit) | iter.collect::<Option<Vec<T>>>() |
Some(vec![1, 2]) |
None (stops at None; Some(3) never evaluated!) |
2. Keep Present Only (Skip None) |
iter.flatten().collect::<Vec<T>>() (or .filter_map(...)) |
vec![1, 2] |
vec![1, 3] |
1. All-or-Nothing Collection into Option<Collection>
Because the standard library implements FromIterator<Option<A>> for Option<V> whenever V: FromIterator<A>, collecting an Iterator<Item = Option<T>> into Option<Vec<T>> (or Option<HashSet<T>>, Option<String>) succeeds with Some(collection) if and only if every item is Some, and short-circuits to None on the first None:
fn parse_all_hex_digits(input: &str) -> Option<Vec<u32>> {
// `ch.to_digit(16)` returns `Option<u32>`;
// collecting into `Option<Vec<u32>>` short-circuits on the first invalid char:
input.chars().map(|ch| ch.to_digit(16)).collect()
}
fn main() {
println!("'1A3F' -> {:?}", parse_all_hex_digits("1A3F"));
println!("'1G3F' -> {:?}", parse_all_hex_digits("1G3F"));
}
'1A3F' -> Some([1, 10, 3, 15])
'1G3F' -> None
2. Skipping None Values with .flatten() or .filter_map()
When None entries represent optional/missing items that should simply be omitted from the output collection, call .flatten() before .collect::<Vec<T>>() (or use .filter_map(|x| ...) when producing the Option<T>):
fn main() {
let raw_playlist = [Some("intro.mp3"), None, Some("theme.mp3"), None];
// `.flatten()` unwraps `Some(x)` and skips `None`:
let valid_tracks: Vec<&str> = raw_playlist.into_iter().flatten().collect();
println!("Valid tracks: {valid_tracks:?}");
}
Valid tracks: ["intro.mp3", "theme.mp3"]