Idiomatic way to choose the first Some() Option?

Viewed 244

If I have a number of Option<T>'s and I want to pick the first one that is Some rather than None - is there an idiomatic way to do that?

My naive approach:

pub fn pick_first_option_available<T>(a: Option<T>, b: Option<T>, c: Option<T>) -> Option<T> {
    match a {
        Some(a) => Some(a),
        None => match b {
            Some(b) => Some(b),
            None => match c {
                Some(c) => Some(c),
                None => None,
            },
        },
    }
}

One obvious issue with the above is that it's limited to a fixed number of Options (3). I would prefer to have a more general function.

There is a somewhat related thread here, but it tackles summing instead of picking options.

2 Answers

Yes, there's a simple and idiomatic way:

a.or(b).or(c)

You don't usually define a function just for this.

Option#or

As @DenysSeguret answer and you could even abstract it for a generic number of options:

use std::array;


pub fn pick_first_option_available<T, const N: usize>(options: [Option<T>; N]) -> Option<T> {
    array::IntoIter::new(options).reduce(Option::or).flatten()
}

Playground

Also, looks like unpopular but still a way of doing it other than Option::or with a simple loop:

use std::array;

pub fn pick_first_option_available<T>(a: Option<T>, b: Option<T>, c: Option<T>) -> Option<T> {
    for option in array::IntoIter::new([a, b, c]){
        if option.is_some() {
            return option;
        }
    }
    None
}

Playground

Related