简体   繁体   中英

Moving a mutable trait object reference into a box

How do I move a mutable trait object reference into a box? eg 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);
}

(playpen link)

... 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?

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM