为什么`Option` 支持`IntoIterator`? [英] Why does `Option` support `IntoIterator`?

查看:24
本文介绍了为什么`Option` 支持`IntoIterator`?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图迭代字符串向量的一个子部分,即 Vec 的一个子切片.在每次迭代中,我想将字符串作为切片传递给函数.

I was trying to iterate over a subsection of a vector of strings, i.e. a subslice of Vec<String>. Within each iteration, I wanted to pass the string as a slice to a function.

我没有注意到 Vec::get 返回一个 Option,并认为我可以直接迭代返回值:

I didn't notice that Vec::get returns an Option, and thought I could just directly iterate over the return value:

fn take_str(s: &str) {
    println!("{}", s);
}

fn main() {
    let str_vec: Vec<String> = ["one", "two", "three", "uno", "dos", "tres"]
        .iter()
        .map(|&s| s.into())
        .collect();
    for s in str_vec.get(0..3) {
        take_str(&s);
    }
}

error[E0308]: mismatched types
  --> src/main.rs:11:18
   |
11 |         take_str(&s); // Type mismatch: found type `&&[std::string::String]`
   |                  ^^ expected `str`, found `&[String]`
   |
   = note: expected reference `&str`
              found reference `&&[String]`

我期望 s 是一个 String,但它实际上是 &[String].这是因为我的 for 循环正在迭代 Vec::get() 返回的 Option.

I was expecting s to be a String, but it's actually &[String]. This is because my for loop is iterating over the Option returned by Vec::get().

我还写了下面的代码,它演示了for循环实际上是在解包一个Option:

I also wrote the following code, which demonstrates that the for loop is in fact unwrapping an Option:

let foo = Option::Some(["foo".to_string()]);
for f in foo {
    take_str(&f); // Same error as above, showing `f` is of type `&[String]`
}

这令人难以置信的混乱;我从没想过(直到我写了这段代码并弄清楚它实际在做什么)Option 可以通过 迭代 来解包.为什么支持?迭代 Option 有什么用例?

This is incredibly confusing; I never expected (until I wrote this code and figured out what it's actually doing) that Option could be unwrapped by iterating over it. Why is that supported? What use case is there for iterating over an Option?

推荐答案

迭代 Option 有什么用例?

一句话,我最喜欢的理由是扁平化:

My favorite reason, in a word, is flatten:

fn main() {
    let results = [Some(1), None, Some(3), None];
    let sum: i32 = results.into_iter().flatten().sum();
    println!("{}", sum)
}

在 Rust 1.29 之前,你可以使用 flat_map:

Before Rust 1.29, you can use flat_map:

fn main() {
    let results = vec![Some(1), None, Some(3), None];
    let sum: i32 = results.into_iter().flat_map(|x| x).sum();
    println!("{}", sum)
}

Option 可以被认为是一个可以容纳零个或一个元素的容器.将其与 Vec 进行比较,后者可以包含零个或多个元素.在很多方面,Option一个容器,就像一个Vec

Option can be thought of as a container that can hold exactly zero or one elements. Compare this to a Vec, which can hold zero or many elements. In a large set of ways, an Option is a container just like a Vec!

实施 IntoIterator 允许 Option 参与更多的 API.

Implementing IntoIterator allows Option to participate in a larger share of APIs.

请注意,出于类似的原因,IntoIteratorResult 实现.

Note that IntoIterator is also implemented for Result, for similar reasons.

这太令人困惑了

是的,这就是为什么 Clippy 有一个为它整理:

Yes, it is, which is why Clippy has a lint for it:

warning: for loop over `str_vec.get(0..3)`, which is an `Option`. This is more readably written as an `if let` statement
  --> src/main.rs:10:14
   |
10 |     for s in str_vec.get(0..3) {
   |              ^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(clippy::for_loops_over_fallibles)]` on by default
   = help: consider replacing `for s in str_vec.get(0..3)` with `if let Some(s) = str_vec.get(0..3)`
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles

这表明,对于程序员来说,Option 在某些方面不像容器.

This shows that there are ways that an Option is not like a container to a programmer.

这篇关于为什么`Option` 支持`IntoIterator`?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆