Is there a way to move a trait object?

I am using some trait objects, simplified down to:

fn main() {
    let item = Box::new(Thingy { buf: vec![1] }) as Box<Thing>;
    let buf = item.to_inner();
}

trait Thing {
    fn to_inner(self) -> Vec<u8>;
}

struct Thingy {
    buf: Vec<u8>,
}

impl Thing for Thingy {
    fn to_inner(self) -> Vec<u8> {
        self.buf
    }
}

This gives a compilation error

movetrait.rs:5:15: 5:19 error: cannot move a value of type Thing: the size of Thing cannot be statically determined [E0161]
movetrait.rs:5     let buf = item.to_inner();

which is understandable. I am using a trait object because the instances need to be dynamically determined. But, I'd still like some way of being able to pull the data out of the object. I'm working around this by using mem::replace to replace it with an empty Vec<u8>, however, this leaves my object in an invalid state (a safe state, but invalid as far as the program goes). It'd be nice to convey the proper move semantics.

Is there a way of indicating a move of a trait object, or another way of making sure this object is known to be invalid after its buffer is moved out?

4 Likes

Does this work for you?

fn main() {
    let item = Box::new(Thingy { buf: vec![1] }) as Box<Thing>;
    let buf = item.to_inner();
}

trait Thing {
    fn to_inner(self: Box<Self>) -> Vec<u8>;
}

struct Thingy {
    buf: Vec<u8>,
}

impl Thing for Thingy {
    fn to_inner(self : Box<Self>) -> Vec<u8> {
        self.buf
    }
}
11 Likes

Yes. I couldn't figure out the syntax to make self boxed.

This suggestion works because the author is in control of trait Thing but if you are consuming an existing library, how do you work around?

This is the same issue that prevents Box<FnOnce()> from being callable, if I'm not mistaken. For that special case, there is now an unstable workaround Box<FnBox()>, but it would be nice to have a general solution here.

Is there a fundamental reason why Box<Trait> and moving or is it just a limitation of the current compiler? I would be thankful to anyone that would post a clear explanation of why the compiler cannot currently support this (in terms of how Traits and Box are compiled).

6 Likes