【问题标题】:How do I convert a list of Option<T> to a list of T when T cannot be copied? [duplicate]当无法复制 T 时,如何将 Option<T> 列表转换为 T 列表? [复制]
【发布时间】:2015-08-15 19:13:28
【问题描述】:

如何获取Vec&lt;Option&lt;T&gt;&gt;,其中T 无法复制,并解开所有Some 值?

我在map 步骤中遇到错误。我很高兴转移原始列表的所有权并“扔掉”Nones。

#[derive(Debug)]
struct Uncopyable {
    val: u64,
}

fn main() {
    let num_opts: Vec<Option<Uncopyable>> = vec![
        Some(Uncopyable { val: 1 }),
        Some(Uncopyable { val: 2 }),
        None,
        Some(Uncopyable { val: 4 }),
    ];

    let nums: Vec<Uncopyable> = num_opts
        .iter()
        .filter(|x| x.is_some())
        .map(|&x| x.unwrap())
        .collect();
    println!("nums: {:?}", nums);
}

Playground

这会导致错误

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:17:15
   |
17 |         .map(|&x| x.unwrap())
   |               ^-
   |               ||
   |               |hint: to prevent move, use `ref x` or `ref mut x`
   |               cannot move out of borrowed content

【问题讨论】:

    标签: iterator rust optional


    【解决方案1】:

    您根本不需要复制Uncopyable,如果您可以将引用的Vec 使用到原始Vec 中:

    let nums: Vec<&Uncopyable> = num_opts.iter().filter_map(|x| x.as_ref()).collect();
    //            ^ notice the & before Uncopyable?
    

    如果您必须使用需要 &amp;[Uncopyable] 的 API,这可能对您不起作用。在这种情况下,使用Matthieu M.'s solution 可以简化为:

    let nums: Vec<Uncopyable> = num_opts.into_iter().filter_map(|x| x).collect();
    

    【讨论】:

      【解决方案2】:

      在 Rust 中,当您需要一个值时,您通常希望移动元素或克隆它们。

      由于move比较通用,这里it is,只需要改两处:

      let nums: Vec<Uncopyable> = num_opts
          .into_iter()
      //  ^~~~~~~~~~~~-------------- Consume vector, and iterate by value
          .filter(|x| x.is_some())
          .map(|x| x.unwrap())
      //       ^~~------------------ Take by value
          .collect();
      

      由于llogiq points outfilter_map 已经专门过滤掉None

      let nums: Vec<Uncopyable> = num_opts
          .into_iter()
      //  ^~~~~~~~~~~~-------- Consume vector, and iterate by value
          .filter_map(|x| x)
      //              ^~~----- Take by value
          .collect();
      

      然后它就可以工作了(消耗num_opts)。

      【讨论】:

      • 这比我的解决方案还要好(除非你想保留原始向量——你不能同时拥有两者)。请注意,您仍然可以使用filter_map 使其更短
      • @lllogiq:我不清楚 Uncopyable 是否也意味着非克隆;所以也许 OP 会接受使用.cloned() 的解决方案。感谢漂亮的filter_map
      • 不客气。感谢into_iter()
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-23
      • 1970-01-01
      • 2016-09-28
      • 1970-01-01
      • 1970-01-01
      • 2015-09-12
      • 2010-10-14
      相关资源
      最近更新 更多