简体   繁体   English

Rust 在 while let 中堆叠可选

[英]Rust stacked optional in while let

I am really new in rust, and while going through the rustlings exercises I found something I do not fully understand regarding stacked Options.我真的是 rust 新手,在进行 rustlings 练习时,我发现了一些关于堆叠选项的东西我并不完全理解。

Given the following code:给定以下代码:

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

I would expect to see the following output:我希望看到以下输出:

Number: 24
Number: 42

But I guess as soon as rust encounters the None , the while loop exits, only printing the 24但我想只要 rust 遇到None ,while循环就会退出,只打印 24

What would be the most idiomatic rust code to iterate and unwrap optional values?迭代和解包可选值的最惯用的 rust 代码是什么? The closest that I got would look something like this:我得到的最接近的看起来像这样:

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

Or it could also be done by checking the existence in a for loop:或者也可以通过检查 for 循环中的存在来完成:

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

Another nice way to write this code is编写此代码的另一种好方法是

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

The flatten() method on an iterator treats each item of the iterator as an iterator, and returns an iterator over all these iterators chained together.迭代器上的flatten()方法将迭代器的每个项目视为一个迭代器,并返回一个迭代器,该迭代器覆盖所有链接在一起的迭代器。 Option is an iterator that yields one element if it is Some , or none for None , so flatten() is exactly what we want here. Option是一个迭代器,如果它是Some则产生一个元素,或者 None 为None ,所以flatten()正是我们想要的。

Of course you could also write this using for_each() , but for code with side effects I generally prefer for loops.当然你也可以用for_each()来写,但是对于有副作用的代码,我通常更喜欢for循环。

I would expect to see the following output: [...]我希望看到以下输出:[...]

A while loop that encounters a false condition exits - but that's not specific to Rust, it's just how while loops work.遇到错误条件的while循环退出 - 但这不是 Rust 特有的,它只是while循环的工作方式。

An idiomatic solution would probably combine your last two snippets:一个惯用的解决方案可能会结合你的最后两个片段:

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

Just a simple for loop containing an if let , no unwrapping required.只是一个包含if let的简单for循环,不需要展开。

Another idiomatic variant is to use iterator adapters:另一个惯用的变体是使用迭代器适配器:

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

Note that here we could use filter(Option::is_some) , but then we would be left with options and would have to use unwrap() to get to the values.请注意,在这里我们可以使用filter(Option::is_some) ,但是我们将留下选项,并且必须使用unwrap()来获取值。 This is where filter_map() comes in useful: it filters the Some values (after applying the map function), and at the same time extracts the values inside.这就是filter_map()派上用场的地方:它过滤Some值(在应用 map 函数之后),同时提取里面的值。 opt.as_ref() serves to trivially convert &Option<T> , obtained from iterating a vector of options by reference, to Option<&T> which filter_map expects returned. opt.as_ref()用于将&Option<T>简单地转换为通过引用迭代选项向量获得的 &Option<T> 到filter_map期望返回的Option<&T>

Using and_then to filter out the None 's and only delivering Some 's to the programs working part:使用and_then过滤掉None并且只将Some传递给程序工作部分:

let vector = vec![Some(24), None, Some(42)];
for num in vector.iter() {
    num.and_then::<i32, fn(i32) -> Option<i32>>(|n| {
        println!("{}", n);  // …working part
        None
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM