为什么我可以直接匹配选项数组,而不能直接匹配包含选项数组的变量?

时间:2018-06-23 23:57:31

标签: rust

以下代码编译:

fn consume(_: Box<u64>) {}
let tuple = (Some(Box::new(1)), Some(Box::new(2)));
match tuple {
    (Some(x), Some(y)) => {
        consume(x);
        consume(y);
    }
    _ => (),
}

以下代码编译:

fn consume(_: Box<u64>) {}
match [Some(Box::new(1)), Some(Box::new(2))] {
    [Some(x), Some(y)] => {
        consume(x);
        consume(y);
    }
    _ => (),
}

但是此代码无法编译:

fn consume(_: Box<u64>) {}
let array = [Some(Box::new(1)), Some(Box::new(2))];
match array {
    [Some(x), Some(y)] => {
        consume(x);
        consume(y);
    }
    _ => (),
}

编译器说:

error[E0382]: use of moved value: `(array[..] as std::prelude::v1::Some).0`
 --> src/main.rs:5:24
  |
5 |         [Some(x), Some(y)] => {
  |               -        ^ value used here after move
  |               |
  |               value moved here
  |
  = note: move occurs because the value has type `std::boxed::Box<u64>`, which does not implement the `Copy` trait

为什么要编译第一和第二个版本,而不是第三个版本?

2 个答案:

答案 0 :(得分:3)

意外地,第三版没有编译。如here所述,匹配盒装值时会发生相同的问题。

从链接的答案中引用错误的解释:

  

我唯一的猜测是Box的所有权移到了第一个   参数,提取参数,然后编译器尝试移动它   再次进入下一个参数。

用“ array”替换“ Box”,您将获得匹配数组时的解释。链接答案中提供的一种解决方案也适用于匹配数组-使用花括号将Box / array完全移动到match表达式中:

fn consume(_: Box<u64>) {}
let array = [Some(Box::new(1)), Some(Box::new(2))];
match {array} {
    [Some(x), Some(y)] => {
        consume(x);
        consume(y);
    }
    _ => (),
}

答案 1 :(得分:3)

以下是代码的简化版本:

struct NonCopy;

fn main() {
    // OK
    let tuple = (Some(NonCopy), Some(NonCopy));
    if let (Some(_x), Some(_y)) = tuple {}

    // OK
    if let [Some(_x), Some(_y)] = [Some(NonCopy), Some(NonCopy)] {}

    // Fails
    let array = [Some(NonCopy), Some(NonCopy)];
    if let [Some(_x), Some(_y)] = array {}
}

好消息

此代码在non-lexical lifetimes are enabled时保持原样。

坏消息

非词汇生存期还不稳定。

解决方法

将数组的所有权明确转移到matchif let头表达式中:

let array = [Some(NonCopy), Some(NonCopy)];
if let [Some(_x), Some(_y)] = { array } {}

说明

借阅检查器的当前实现是基于AST的,而将来的实现将是基于MIR的。在较高的层次上,您可以将其视为“处理我键入的代码”(AST)和“处理代码中的逻辑数据流”(MIR)。

某些“黑客”已添加到AST借阅检查器中,这就是为什么您可以成功使用数组文字而不是变量的原因。借助MIR借阅检查器,此类大型黑客将消失,借阅检查器也将变得更加精确,从而可以编译更多代码。