【问题标题】:How can I iterate on an Option<Vec<_>>?如何迭代 Option<Vec<_>>?
【发布时间】:2021-08-26 18:54:16
【问题描述】:

我正在尝试在 Option&lt;Vec&lt;&gt;&gt; 上进行迭代。

#[derive(Debug)]
pub struct Person {
    pub name: Option<String>,
    pub age: Option<u64>,
}

#[derive(Debug)]
pub struct Foo {
    pub people: Option<Vec<Person>>,
}

天真地我在使用

for i in foo.people.iter() {
    println!("{:?}", i);
}

我实际上是显示整个Vec,而不是遍历Vec 的所有元素。就像我在迭代 Option 的唯一引用。

使用以下内容,我正在迭代 Vec 内容:

for i in foo.people.iter() {
    for j in i.iter() {
        println!("{:?}", j);
    }
}

我不确定这是不是最令人愉快的语法,我相信您应该首先打开 Option 以实际迭代集合。

如果你总是有一个单一的参考,我看不出你可以在哪里实际使用Option::iter

Here 是游乐场的链接。

【问题讨论】:

  • 有什么问题?
  • 我不明白在什么情况下你应该使用 Option.iter(),我可能错误地认为它总是返回一个项目。
  • @XavierT。 Option::iter 专为您希望将选项视为零元素或一元素容器的情况而设计。它对我来说似乎也不是很有用,但就是这样。
  • @user4815162342 let foo: Vec&lt;Option&lt;T&gt; = vec![]; let bar: Vec&lt;T&gt; = foo.into_iter().flat_map(|x| x).collect();.

标签: rust


【解决方案1】:

正如 cmets 中提到的另一个答案,我会使用以下内容:

// Either one works
foo.people.iter().flatten()
foo.people.iter().flat_map(identity)

Option&lt;T&gt; 上的 iter 方法将返回一个包含一个或零个元素的迭代器。

flatten 获取每个元素(在本例中为 &amp;Vec&lt;Person&gt;)并展平它们的嵌套元素。

这与使用identity 执行flat_map 相同,它获取每个元素(在本例中为&amp;Vec&lt;Person&gt;)并展平它们的嵌套元素。

两条路径都生成Iterator&lt;Item = &amp;Person&gt;

【讨论】:

    【解决方案2】:

    Option 有一个iter method,它“迭代可能包含的值”,即提供Option 中的单个值(如果选项是Some),或者根本没有值(如果选项是None)。因此,如果您想将选项视为容器,其中None 表示容器为空,Some 表示它包含单个元素,则它很有用。

    要遍历底层元素的值,您需要从foo.people.iter() 切换到foo.people.unwrap().iter()foo.people.unwrap_or_else(Vec::new).iter(),这取决于您是希望程序在遇到None 人时发生恐慌还是不进行迭代。

    可编译示例in the playground

    【讨论】:

    • 代替unwrap 也可以简单地将if let Some(ref v) = foo.people {} 包裹在迭代周围
    • @ker 这是另一种选择(不是双关语),但它确实需要在循环周围增加一个缩进级别。当代码实际上期望选项不是None 并想要断言时,unwrap() 仍然有用。
    • 如果我一直想遍历人,我可能会做foo.people.iter().flat_map(|v|v.iter())None 会给出一个空的迭代器,否则我们会给出向量的所有元素。
    • @Lukazoid 不需要v.iter();只需 v 即可。
    • @Shepmaster 我没有发现flat_map 处理IntoIterator,那就更好了。
    【解决方案3】:

    使用Option::as_derefOption::unwrap_or_default

    for i in foo.people.as_deref().unwrap_or_default() {
        println!("{:?}", i);
    }
    

    Option::as_deref&amp;Option&lt;Vec&lt;T&gt;&gt; 转换为Option&lt;&amp;[T]&gt;,然后unwrap_or_default 返回&amp;[T] 或默认值(一个空切片)。然后,您可以直接对其进行迭代。

    另见:

    【讨论】:

      【解决方案4】:

      如果您不需要具有 IntoIterator 实现的实际值,则可以改用显式 if let

      if let Some(x) = foo.people {
          for i in x {
              // work with i here
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-22
        • 1970-01-01
        • 2019-06-13
        • 1970-01-01
        • 2015-05-13
        相关资源
        最近更新 更多