Struct containing vector of trait objects


#1
trait A {
    fn a(&self) -> bool;
}

struct B {}
struct C {}

impl A for B {
    fn a(&self) -> bool {
        true
    }
}
impl A for C {
    fn a(&self) -> bool {
        false
    }
}

struct D<T: A> {
    x: Vec<Box<T>>,
}

fn main() {
    let v: Vec<Box<A>> = vec![Box::new(B {}), Box::new(C {})];
    assert_eq!(2, v.len());

    let mut d = D { x: vec![] };
    d.x.push(Box::new(B {}));
    d.x.push(Box::new(C {}));
    assert_eq!(2, d.x.len());
}
error[E0308]: mismatched types
  --> <anon>:29:23
   |
29 |     d.x.push(Box::new(C {}));
   |                       ^^^^ expected struct `B`, found struct `C`
   |
   = note: expected type `B`
              found type `C`

(Example on Rust Playground)

Hi everyone – I’m struggling to understand why the two cases above are treated differently, and how I can give the compiler enough info to understand that the second case (vector inside struct) is okay. Do I need another type annotation somewhere?

Thanks in advance for any help. :slight_smile:


#2
struct D<T: A> {
    x: Vec<Box<T>>,
}

This isn’t a vector of trait objects, its a generic type. The T parameter has to be a specific type that implements A. What you want is this:

struct D {
    x: Vec<Box<A>>,
}

#3

Thank you @withoutboats! You’re right. I think I must have arrived at the generic while trying to understand earlier compiler errors.

Incidentally – if I was going to stick with the generic, would there be a way to make the example work?


#4

If you were forced to use a generic, you could make a wrapper around the trait objects that implements A to have a concrete type that just forward the call to the inner trait object.

struct E {
    inner: Box<A>,
}

impl A for E {
    fn a(&self) -> bool {
        self.inner.a()
    }
}

#5

I see what you mean, so that way I’m dealing with a Vec<E> and hiding the type one level deeper. Thanks @ndusart :slight_smile:


#6

You can also just:

impl A for Box<A> { }

Or even:

impl<T: ?Sized + A> A for Box<T> { }