【问题标题】:Rust stacked optional in while letRust 在 while let 中堆叠可选
【发布时间】:2020-08-27 13:54:25
【问题描述】:

我真的是 rust 新手,在进行 rustlings 练习时,我发现了一些关于堆叠选项的东西我并不完全理解。

给定以下代码:

let vector = vec![Some(24), None, Some(42)];
let mut iter = vector.iter();
while let Some(Some(number)) = iter.next() {
    println!("Number: {}", number);
}

我希望看到以下输出:

Number: 24
Number: 42

但我猜只要 rust 遇到 None,while 循环就会退出,只打印 24

迭代和解包可选值的最惯用的 rust 代码是什么? 我得到的最接近的看起来像这样:

let mut iter = vector.iter();
while let Some(iterNext) = iter.next() {
    if let Some(num) = iterNext {
        println!("Number: {}", num);
    }
}

或者也可以通过在 for 循环中检查是否存在来完成:

for opt in &vector {
    if opt.is_some() {
        println!("Number: {}", opt.unwrap());
    }
}

【问题讨论】:

  • 确实,当它遇到第二个元素,即Some(None)while 循环就会中断。什么是“更惯用”或多或少见仁见智,但我肯定更喜欢if let 而不是is_some / unwrap 版本。 if let 的全部意义在于,您可以避免手动检查/解包选项。

标签: rust


【解决方案1】:

编写此代码的另一种好方法是

for num in vector.iter().flatten() {
    println!("{}", num);
}

迭代器上的flatten() 方法将迭代器的每一项都视为一个迭代器,并返回一个迭代器链接在一起的所有这些迭代器。 Option 是一个迭代器,如果它是 Some,则产生一个元素,或者对于 None 不产生一个元素,所以 flatten() 正是我们想要的。

当然你也可以用for_each()写这个,但是对于有副作用的代码我一般更喜欢for循环。

【讨论】:

    【解决方案2】:

    我希望看到以下输出:[...]

    遇到错误条件的 while 循环退出 - 但这不是 Rust 特有的,while 循环就是这样工作的。

    一个惯用的解决方案可能会结合你最后两个 sn-ps:

    for opt in &vector {
        if let Some(num) = opt {
            println!("Number: {}", num);
        }
    }
    

    只是一个简单的for 循环,其中包含一个if let,不需要解包。

    另一个惯用的变体是使用迭代器适配器:

    vector
        .iter()
        .filter_map(|opt| opt.as_ref())
        .for_each(|num| println!("{}", num));
    

    请注意,在这里我们可以使用filter(Option::is_some),但是我们将留下选项,并且必须使用unwrap() 来获取值。这是哪里 filter_map() 很有用:它过滤 Some 值(在应用 map 函数之后),同时提取里面的值。 opt.as_ref() 用于将&Option<T>(通过引用迭代选项向量获得)转换为Option<&T>filter_map 期望返回。

    【讨论】:

      猜你喜欢
      • 2023-02-23
      • 2018-06-05
      • 2019-07-02
      • 2019-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      相关资源
      最近更新 更多