Trait-object with Generics issue

Hello, I'm trying to implement some kind of parser. To do this I'm relying on the trait-objects manual (https://doc.rust-lang.org/book/ch17-02-trait-objects.html#implementing-the-trait). I have no troubles implementing this kind of logic with dyn operator, but it is not possible for me to make it with Generics. I know that by default generics allows use just one type per time, but how the same kind of code works for guys in the Rust docs? Could you help me to figure out where is the misunderstanding please?

trait StateSpecificParser {
    fn extract(&self);
}

struct FirstState {}
impl StateSpecificParser for FirstState {
    fn extract(&self){}
}

struct SecondState {}
impl StateSpecificParser for SecondState {
    fn extract(&self){}
}

struct ParserStruct<T: StateSpecificParser> {
    count: u8,
    pub states: Vec<T>
}

impl<T> ParserStruct<T> where T: StateSpecificParser {
    pub fn exec(&self){
        for state in self.states.iter() {
            state.extract();
        }
    }
}

fn main() {
    let parser = ParserStruct{
        count: 10,
        states: vec![Box::new(FirstState{}), Box::new(SecondState{})]
    };

    parser.exec();
}

Compilation output:

error[E0308]: mismatched types
  --> src/main.rs:31:55
   |
31 |         states: vec![Box::new(FirstState{}), Box::new(SecondState{})]
   |                                                       ^^^^^^^^^^^^^ expected struct `FirstState`, found struct `SecondState`

error[E0277]: the trait bound `std::boxed::Box<FirstState>: StateSpecificParser` is not satisfied
  --> src/main.rs:29:18
   |
15 | struct ParserStruct<T: StateSpecificParser> {
   | ------------------------------------------- required by `ParserStruct`
...
29 |     let parser = ParserStruct{
   |                  ^^^^^^^^^^^^ the trait `StateSpecificParser` is not implemented for `std::boxed::Box<FirstState>`

error[E0599]: no method named `exec` found for struct `ParserStruct<std::boxed::Box<FirstState>>` in the current scope
  --> src/main.rs:34:12
   |
15 | struct ParserStruct<T: StateSpecificParser> {
   | ------------------------------------------- method `exec` not found for this
...
34 |     parser.exec();
   |            ^^^^ method not found in `ParserStruct<std::boxed::Box<FirstState>>`
   |
   = note: the method `exec` exists but the following trait bounds were not satisfied:
           `std::boxed::Box<FirstState> : StateSpecificParser`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `exec`, perhaps you need to implement it:
           candidate #1: `std::os::unix::process::CommandExt`

error: aborting due to 3 previous errors

You want it to coerce both boxes to Box<dyn Parser>, but it's trying to make a Vec<Box<FirstState>> and complaining the second one doesn't match. To fix this, explicitly cast the first box to a trait object, and the rest will be automatically coerced.

Thanks you. Could you please provide an example how it should be look like? And do you know why it is correct in the Rust book (https://doc.rust-lang.org/book/ch17-02-trait-objects.html#implementing-the-trait)?

you can cast it like this: Box::new(...) as Box<dyn YourTrait>. I'm not sure exactly which example you're referring to, but it's likely because you're using generics. If your type used Vec<Box<dyn YourTrait>> and not Vec<Box<T>> for T: YourTrait, type inference would figure out the coercion without you having to cast the first one.

Listing 17-6 + Listing 17-6 + Listing 17-6 + Listing 17-9 from the page I mentioned before. Can you take a look? How different structs are boxed without using dyn. Just generics.

If you use generics, you can only use a single type.

Thank you. It looks like I did not understand the article correctly. Now it is clear for me.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.