Trait objects and structs

Hey guys!

I think my current understanding of trait objects is slightly wrong. I have already read the chapter dedicated to them in the rust book twice but for some reason it's still not apparent to me.

Why is "this" code not working but the "other" code is:

this code

pub trait MyTrait {}

pub struct MyStruct;

impl MyTrait for MyStruct {}

fn main() {
    // I am not referring to the size problem but to the
    // "expected trait object `dyn MyTrait`, found struct
    // `MyStruct`" error I'm getting.
    let x: dyn MyTrait = MyStruct {};

}

other code

pub trait MyTrait {}

pub struct MyStruct;

impl MyTrait for MyStruct {}

fn main() {

    let x: Box<dyn MyTrait> = Box::new(MyStruct {});

}

Best regards,
Dominik

I think the important thing to realize is that the trait object type dyn MyTrait is a separate type from MyStruct. Neither is a sub-type of the other or anything like that, it's just possible to convert between them in certain cases. For example, in the latter example, you first create a Box<MyStruct>, which is then converted into a Box<dyn MyTrait>.

Your first example does not work because there's no conversion for a bare MyStruct to a bare dyn MyTrait. The type dyn MyTrait cannot exist without being behind a pointer in the first place, so it makes no sense to have the conversion.

1 Like

Thanks for your answer!

I now get why this does not work:

pub trait Behaviour {}

pub trait MyTrait<T: Behaviour> {}

pub struct MyStruct;

pub struct StructBehaviour;

impl Behaviour for StructBehaviour {}

impl MyTrait<StructBehaviour> for MyStruct {}

fn main() {
    let a: Vec<Box<dyn MyTrait<dyn Behaviour>>> = vec![];

    a.push(Box::new(MyStruct {}));

}

But I really can not think of any other way to get it done. Is there any standard way to do such things?

Best regards,
Dominik

In this case you can turn off the requirement that T from MyTrait<T> must be sized like this:

pub trait MyTrait<T: Behaviour + ?Sized> {}

Of course, if you start trying to use T in ways that dyn Behaviour may not be used, you will get errors from that. For example, you can no longer define a method that returns a T. Anyway, it still fails:

error[E0277]: the trait bound `MyStruct: MyTrait<dyn Behaviour>` is not satisfied
  --> src/main.rs:16:12
   |
16 |     a.push(Box::new(MyStruct {}));
   |            ^^^^^^^^^^^^^^^^^^^^^ the trait `MyTrait<dyn Behaviour>` is not implemented for `MyStruct`
   |

This is because dyn Behaviour is a different type than StructBehaviour, and MyStruct only implements MyTrait<StructBehaviour>, which is different from MyTrait<dyn Behaviour>. Of course, you could add this impl too:

impl MyTrait<dyn Behaviour> for MyStruct {}

At this point, it would compile. That said, it's not clear that this helps you achieve your goals.

1 Like

If you have further questions, I declare XY problem and ask you to describe what you are actually trying to do.

2 Likes