在Rust中,Option\<number\>的最大值惯用方法是什么?

4

我有一个在Option中的数字。我需要用它和另外一个值的最大值来替换它,如果我的数字是None,那么就使用那个其他的值。

我写了一个函数来实现这个功能:

fn max(a: Option<u32>, b: u32) -> Option<u32> {
    if a.is_some() {
        Some(std::cmp::max(a.unwrap(), b))
    } else {
        Some(b)
    }
}

但我一直在想,是否有更好、更简洁的方法可以使用 Option 的方法实现。你能帮忙吗?


一种简短的写法是:max(a.unwrap_or(0), b)。(如果您想将代码未来防止类型更改为i32,还可以使用u32::MIN。) - user4815162342
3个回答

6

Max:

Option<T> 实现了 Ord,当 T 实现了 Ord 时,可以像这样实现您的函数:

fn max(a: Option<u32>, b: u32) -> Option<u32> {
    std::cmp::max(a, Some(b))
}

Playground


请注意:

对于每个 T: Ord, Some<T> 都大于 None,这符合您的要求。

虽然此规则未被记录,但我们可以证明:

由于 Ord 类型形成了一个全序。这意味着它们需要是传递性的;如果 None 小于 Some(MIN),那么 None 将小于集合中(Option<T>)的任何其他值,因为 Some(MIN) 小于集合中除 None 以外的任何值。

assert!(Some(std::i64::MIN) > None);

Min:

您还可以通过添加额外的or来扩展std::cmp::min,这种方法也适用于max情况,但是这不是必须的,因为会有额外的检查和值b的副本比较max解决方案。

fn min(a: Option<u32>, b: u32) -> Option<u32> {
    std::cmp::min(a.or(Some(b)), Some(b))
}

游乐场


真的很聪明!太遗憾了,它只适用于 max(在我的代码中,最小值和最大值都具有相同的 Option<number> 结构)。 - George Shuklin
2
@GeorgeShuklin 谢谢,我已经添加了“min”的另一种解决方案,希望能有所帮助。 - Ömer Erden

5

使用 map

fn max(a: Option<u32>, b: u32) -> Option<u32> {
    a.map(|v| std::cmp::max(v, b))
}

Playground

或者使用map_or方法对未包装的项进行默认处理:

fn max(a: Option<u32>, b: u32) -> Option<u32> {
    a.map_or(Some(b), |v| Some(std::cmp::max(v, b)))
}

游乐场

在这种情况下,你实际上不需要返回的Option

fn max(a: Option<u32>, b: u32) -> u32 {
    a.map_or(b, |v| std::cmp::max(v, b))
}


如果aNone,第一个例子可以正常工作。 - George Shuklin
@GeorgeShuklin,是的,我正在准备map_or。 - Netwave
1
第二个,谢谢。Some(a.map_or(b, |v| std::cmp::max(v, b))) - George Shuklin
@GeorgeShuklin,对于第二种情况,请注意您实际上不需要该选项,因为您保证会有一个返回值。 - Netwave
我需要将它保存回一个结构体的字段中,所以,不幸的是,选项是必需的。 - George Shuklin

0

...对于那些函数式编程迷...

使用单子属性的另一种方法,也许这可以帮助你理解单子,它允许在给定 Thing<A> 的情况下应用一个函数 A -> Thing<B> 来获得一个 Thing<B>

and_then :: Thing<A> -> (A -> Thing<B>) -> Thing<B>

fn max(a: Option<u32>, b: u32) -> u32 {
    a.and_then(|v| Some(std::cmp::max(v, b))).unwrap_or(b)
}

然后我需要将它放回到选项中。尊重单子,我不认为你的代码比原始代码更易读或更简洁。 - George Shuklin
我知道,只是添加一个不同的方法。 - cdecompilador

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