当解构一对Box时发生了附带移动的错误

5
以下两行代码:

let x = Box::new(("slefj".to_string(), "a".to_string()));
let (a, b) = *x;

产生错误:

error[E0382]: use of moved value: `x`
 --> src/main.rs:3:13
  |
3 |     let (a, b) = *x;
  |          -  ^ value used here after move
  |          |
  |          value moved here
  |
  = note: move occurs because `x.0` has type `std::string::String`, which does not implement the `Copy` trait

有趣的是,如果我对一个包含多个部分的枚举类型进行此操作,我会得到稍微不同的错误:

enum Tree {
    Nil,
    Pair(Box<Tree>, Box<Tree>),
}

fn main() {
    let x = Box::new(Tree::Nil);

    match *x {
        Tree::Pair(a, b) => Tree::Pair(a, b),
        _ => Tree::Nil,
    };
}

我遇到了错误:

error[E0382]: use of collaterally moved value: `(x:Tree::Pair).1`
  --> src/main.rs:10:23
   |
10 |         Tree::Pair(a, b) => Tree::Pair(a, b),
   |                    -  ^ value used here after move
   |                    |
   |                    value moved here
   |
   = note: move occurs because `(x:Tree::Pair).0` has type `std::boxed::Box<Tree>`, which does not implement the `Copy` trait

为什么会发生这种情况,如何使用 let/match 轻松地解构结构并获取内部部分的所有权?我知道可以先取消引用并为结构命名,但如果我深入模式匹配到一个结构中,那将变得非常冗长。
2个回答

6
你遇到了一个解构和盒子的限制。幸运的是,绕过这些限制很容易。你只需要引入一个新的中介变量来包含整个结构,然后从中进行解构即可:
let x = Box::new(("slefj".to_string(), "a".to_string()));
let pair = *x;
let (a, b) = pair;

第二个例子:
let pair = *x;
match pair {
    Tree::Pair(a, b) => Tree::Pair(a, b),
    _ => Tree::Nil,
};

我也很惊讶你不能使用左侧的框,例如 let Box((a,b)) = x;,我已将其报告为 #22207 - Shepmaster
1
可以使用 box 语法实现,但目前该功能已被特性门控(并且可能会更改)。不确定是否可以使用 Box(结构体)进行解构赋值。 - Renato Zannon
有没有其他解决方法,不需要在结构的每一层都需要一个中间绑定?这种解决方法会使得对深层结构的匹配非常冗长。 - Spencer florence
目前我不知道有什么办法可以解决这个问题。我建议你订阅我发布的问题,以便在修复时收到通知。 - Renato Zannon

1
好消息是,现在默认启用了非词法生命周期,所以您的原始代码可以原样工作:
fn main() {
    let x = Box::new(("slefj".to_string(), "a".to_string()));
    let (a, b) = *x;
}

借贷检查器跟踪盒子外部的移动能力得到增强,使代码能够编译。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接