Why doesn't a generic struct with a Box implement Sized?

I've written up this little example code of a struct that wraps a Trait:

trait HasHello {
    fn hello(&self) -> String;
}

struct Hello1;

impl HasHello for Hello1 {
    fn hello(&self) -> String {
        "hello!".to_string()
    }
}

struct MyStruct<T>
where
    T: HasHello,
{
    t: Box<T>,
}

impl<T> MyStruct<T>
where
    T: HasHello,
{
    fn new(t: T) -> Self {
        Self { t: Box::new(t) }
    }
}

fn main() {
    let _: Vec<MyStruct<dyn HasHello>> = vec![MyStruct::new(Hello1)];
}

(Playground)

I would expect that, regardless of the which implementation HasHello passed to MyType, because the HasHello is passed into a Box<>, the MyType would be Sized because it's just a pointed.

But that isn't the case:

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the size for values of type `dyn HasHello` cannot be known at compilation time
  --> src/main.rs:29:12
   |
29 |     let _: Vec<MyStruct<dyn HasHello>> = vec! [MyStruct::new(Hello1)];
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `dyn HasHello`

What am I misunderstanding about how Sized works? And how would I go about making a Vec of structs wrapping different trait implementers?

The error is confusing, but here is the actual problem: every type parameter has a Sized bound unless you declare otherwise. You need to relax it like so:

struct MyStruct<T: ?Sized> {
    t: Box<T>,
}

impl<T> MyStruct<T>
where
    T: ?Sized + HasHello,
{

(Also, don't put trait bounds on struct declarations, just their impls, unless you have to. It makes things more concise at no cost.)

3 Likes

Also note that to enable coercing MyStruct<Hello1> to MyStruct<dyn HasHello>, you'll have to implement the unstable CoerceUnsized trait for your type. Rust Playground

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.