当T无法复制时,如何将Option <t>列表转换为T列表?

时间:2015-06-02 06:06:37

标签: iterator rust optional

如何使用Vec<Option<T>>,无法复制T并解开所有Some值?

我在map步骤中遇到错误。我很乐意移动原始列表的所有权并且&#34;扔掉&#34; None s。

#[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

2 个答案:

答案 0 :(得分:5)

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

由于移动更为通用,此处为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)。

答案 1 :(得分:3)

如果您可以使用原始Uncopyable Vec的{​​{1}}个引用,则无需复制Vec

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

如果您必须使用需要&[Uncopyable]的API,这可能无法解决问题。在这种情况下,请使用Matthieu M.'s solution,可以缩减为:

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