Search code examples
rusttrait-objects

rust generic type with trait bound when use trait objects


trait MyTrait {
    fn my_f(&self) ;
}

struct A {}
struct B {}

impl MyTrait for A {
    fn my_f(&self) {
        println!("A.my_f()");
    }
}
impl MyTrait for B {
    fn my_f(&self) {
        println!("B.my_f()");
    }
}

struct MyList<T: MyTrait> {
    list: Vec<T>
}

fn main() {
    let list = MyList {
        list: vec![
            Box::new(A{}),
            Box::new(B{})
        ]
    };
}

I followed this article, Using Trait Objects That Allow for Values of Different Types

According to this article:

This restricts us to a Screen instance that has a list of components all of type Button or all of type TextField. If you’ll only ever have homogeneous collections, using generics and trait bounds is preferable because the definitions will be monomorphized at compile time to use the concrete types.

On the other hand, with the method using trait objects, one Screen instance can hold a Vec that contains a Box as well as a Box. Let’s look at how this works, and then we’ll talk about the runtime performance implications.

But this code can't be compiled.


Solution

  • Read more closely the section on Defining a Trait for Common Behavior. It defines Screen in listing 17-4 with a Vec<Box<dyn Draw>>:

    pub struct Screen {
        pub components: Vec<Box<dyn Draw>>,
    }
    

    Then it says:

    we could have defined the Screen struct using a generic type and a trait bound as in Listing 17-6

    Emphasis on the conditional "could". It then goes on to explain why using a generic type and trait bound doesn't work:

    This (1) restricts us to a Screen instance that has a list of components all of type Button or all of type TextField.

    […]

    On the other hand, with the method using trait objects (2), one Screen instance can hold a Vec<T> that contains a Box<Button> as well as a Box<TextField>.

    (1) using a generic type and trait bound

    (2) i.e. with Box<dyn<Draw>>