If I do the following, I get an error:
struct A;
struct B;
fn consume_a(_a: A) {}
fn consume_b(_b: B) {}
struct C(A, B);
impl C {
fn foo(self: Self) {
consume_a(self.0);
consume_b(self.1);
}
}
fn main() {
let c = Box::new(C(A, B));
// Consume internals
let _a = c.0;
let _b = c.1;
}
error[E0382]: use of moved value: `c`
--> src/main.rs:21:9
|
20 | let _a = c.0;
| -- value moved here
21 | let _b = c.1;
| ^^ value used here after move
|
= note: move occurs because `c.0` has type `A`, which does not implement the `Copy` trait
I can achieve the same thing (consumption of internals) doing this:
fn main() {
let c = Box::new(C(A, B));
c.foo();
}
The way it works above (c.foo()
) means that I have moved out of boxed content; how can this happen? None of the API's in Box
's documentation show I can obtain the contained value as a type (i.e. all methods return &T
or &mut T
but not T
)
As you can see in the method, moving out of a struct's field directly works fine, but moving out of a field of a struct that's in a Box
will first move out of the Box
into a temporary variable and then move out of the field of that temporary. Thus when you try to move out of the second field, the Box
has already been destroyed and there's just a temporary left that you can't use.
You can make this work by creating the temporary yourself:
let c2 = *c;
let _a = c2.0;
let _b = c2.1;
Your original code works when non-lexical lifetimes are enabled:
#![feature(nll)]
struct A;
struct B;
fn consume_a(_a: A) {}
fn consume_b(_b: B) {}
struct C(A, B);
impl C {
fn foo(self: Self) {
consume_a(self.0);
consume_b(self.1);
}
}
fn main() {
let c = Box::new(C(A, B));
// Consume internals
let _a = c.0;
let _b = c.1;
}
This indicates that the original failure was simply a weakness of the borrow-checker.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With