The following two lines:
let x = Box::new(("slefj".to_string(), "a".to_string()));
let (a, b) = *x;
produce the error:
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
Interestingly, if I do this with an enumeration type with multiple parts, I get a slightly different error:
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,
};
}
I get the error:
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
Why does this happen, and how can I easily destruct structures with let
/match
and get ownership of the inner parts? I know I can dereference and name the structure first, but that gets horribly verbose if I'm pattern matching deep into a structure.
You have stumbled on a limitation on destructuring and boxes. Luckily, it's easy to work around these. All you need to do is introduce a new intermediary variable that contains the whole structure, and destructure from that:
The second example:
The good news is that your original code works as-is now that non-lexical lifetimes are enabled by default:
The borrow checker's capability to track the moves out of the box is enhanced, allowing the code to compile.