选择第一个 Some() Option 的惯用方法是什么?

7
如果我有一些类型为Option<T>的数字,我希望选择第一个是Some而不是None的数字 - 是否有惯用的方法来实现这一点?
我的朴素方法:
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,
            },
        },
    }
}

以上方法的一个明显问题是只能处理有限数量的选项(3个)。我更希望有一个更通用的函数。

这里有一个相关的主题 链接,但它处理的是相加而不是选择选项。

2个回答

14

是的,有一种简单且符合惯用语的方式:

a.or(b).or(c)

通常情况下你不需要专门为此定义一个函数。

Option#or


哇,太简单了。谢谢! - ilmoi

0

正如@DenysSeguret的回答,您甚至可以将其抽象为通用选项数量:

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()
}

游乐场

此外,看起来还有一种不太流行但仍然可以使用的方法,而不是使用简单循环的Option::or

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
}

游乐场


1
我想知道第一个变量是否会实现短路,这是我们想要的。也许可以使用类似于 iter.skip_while(Option::is_none).map(Option::unwrap).next() 的方法来达到相同的效果,并在第一个 Some 处停止迭代。如果您不喜欢 unwrap,可以使用 scaniter.scan(true, |proceed, opt| proceed.then(|| { *proceed = false; opt })).flatten().next(),但这已经相当晦涩了。 - user4815162342
绝对不要短路 @user4815162342。可能可以按照你说的方法解决。 - Netwave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接