Option<T> and Result<T, E> in Depth

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