Reputation: 5390
How do I move a mutable trait object reference into a box? e.g. I'd perhaps expect
struct A {a:i32}
trait B {
fn dummy(&self) {}
}
impl B for A {}
fn accept_b(x:&mut B) -> Box<B> {
Box::new(*x)
}
fn main() {
let mut a = A{a:0};
accept_b(&a);
}
... to work, but instead it errors out as
<anon>:8:5: 8:13 error: the trait `core::marker::Sized` is not implemented for the type `B` [E0277]
<anon>:8 Box::new(*x)
^~~~~~~~
<anon>:8:5: 8:13 note: `B` does not have a constant size known at compile-time
<anon>:8 Box::new(*x)
^~~~~~~~
<anon>:8:14: 8:16 error: cannot infer an appropriate lifetime due to conflicting requirements
<anon>:8 Box::new(*x)
^~
<anon>:7:33: 9:2 note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the block at 7:32...
<anon>:7 fn accept_b(x:&mut B) -> Box<B> {
<anon>:8 Box::new(*x)
<anon>:9 }
<anon>:8:14: 8:16 note: ...so that expression is assignable (expected `B`, found `B`)
<anon>:8 Box::new(*x)
^~
note: but, the lifetime must be valid for the static lifetime...
<anon>:8:5: 8:17 note: ...so that it can be closed over into an object
<anon>:8 Box::new(*x)
^~~~~~~~~~~~
<anon>:13:14: 13:16 error: mismatched types:
expected `&mut B`,
found `&A`
(values differ in mutability) [E0308]
<anon>:13 accept_b(&a);
^~
error: aborting due to 3 previous errors
... effectively whining that I can't move the trait object into the box. Do I have to put the value in a box first, and then cast that box into a box-of-a-trait later?
Shouldn't the mutability rules transitively ensure that the trait I get in accept_b
is the sole owner of the underlying object and thereby support movement into a box? Or does Rust not record the necessary information to provide that nicety? Am I misunderstanding move vs mutable borrow semantics? What's going on?
Upvotes: 2
Views: 2235
Reputation: 15002
Shouldn't the mutability rules transitively ensure that the trait I get in
accept_b
is the sole owner of the underlying object and thereby support movement into a box?
No, absolutely not. accept_b
is borrowing the reference, not owning it.
The mutability rule only makes you certain that you are the only one borrowing the object, but it does not give you ownership.
It is actually never possible to move out of borrowed content and leaving the reference dandling. If you want to move out of a &mut
reference, you can use functions like std::mem::replace(..)
, but they require you to put an other object in place of the one you are moving out, which in turns involve copying actual memory data, and thus the type must be Sized
.
So no, it is not possible to move out of a &mut T
if T
is not Sized
.
Upvotes: 6