当 Option 为 None 或内部值满足某些条件时,执行某些操作的惯用方法是什么?

问题描述 投票:0回答:9

有没有更惯用的方式来表达如下内容?

fn main() {
    let mut foo: Option<u8> = None;
    match foo {
        Some(foo_val) if ! (foo_val < 5) /* i.e. the negation of my acceptance condition */ => {}
        _ => { foo.replace(5); }
    }
}

大多数时候,除了一只不做任何事情的手臂之外,似乎还有一种替代方案,但我一直无法找到适合这种特殊情况的替代方案。

我想说的是更直接的

if foo.is_none() || /* some way to extract and test the inner value */ { ... }
,或者也许是一些我无法理解的链接技巧。

rust
9个回答
64
投票
//        in None case
//             │       in Some(_) case
//            ┌┴─┐  ┌───────────────────┐    
if foo.map_or(true, |foo_val| foo_val < 5) {
    // ...
}

欲了解更多信息,请参阅

Option::map_or


30
投票

有很多方法可以做到这一点。最简单的(也可以说是最易读的)之一是这样的:

if foo.unwrap_or(0) < 5 {
    ...
}

以上两种情况均成立:

  • foo
    Some
    且值小于
    5
    时;
  • foo
    None
    时。

在一些更复杂的场景中,需要计算“默认”值并且性能至关重要,您可能需要考虑

unwrap_or_else

正如Lukas建议的,也可以使用

map_or
方法。请注意,传递给
map_or
的参数会立即评估,因此如果性能至关重要,您可能需要考虑
map_or_else
作为替代方案。

铁锈1.70+

is_some_and
方法已在 Rust 1.70 中稳定下来。这是一个例子:

if name.is_some_and(|s| s.len() > 50) {
    println!("This is a long name!");
}

在许多情况下,这应该比

map_or
/
map_or_else
更具可读性。


15
投票

您可以使用

filter
(使用条件的否定)和
is_none
来做到这一点:

if foo.filter(|&x| !(x < 5)).is_none() {
    // Here either foo was None or it contained a value less than 5
}

6
投票

自 Rust 1.70.0 (2023-06-02) 起,可以使用

Option::is_some_and
。它是为相反的用例构建的,如问题所示:如果是
false
,则返回
None
:

if foo.is_some_and(|foo_val| foo_val < 5) { 
    // ...
}

6
投票

我不确定我完全理解你的问题,但你可以尝试这样的事情:

fn main() {
    let foo: Option<u8> = None;
    let result = foo.filter(|foo_val| !(*foo_val < 5) ).unwrap_or(5);
    println!("Result: {result}");
}

更多示例请参阅Playground


6
投票

matches! 宏看起来很合适:

if matches!(foo, Some(a) if a>=5) { foo.replace(5) }

铁锈游乐场


3
投票

我会提出另一个解决方案只是为了好玩......

foo = foo.
    or(Some(5)). // if None return Some(5)
    map(|x| if x<5 { 5 } else { x });

或者(对于这个具体例子)

foo = foo.
    or(Some(5)). // if None return Some(5)
    map(|x| u8::max(x, 5));

3
投票

filter
or
,

foo = foo.filter(|a|  *a >= 5)
                .or(Some(5));

0
投票

从 Rust 1.82.0 开始,对于这种情况,我们有

Option::is_none_or

foo.is_none_or(|foo_val| foo_val < 5)
© www.soinside.com 2019 - 2024. All rights reserved.