Confusion about a collection of structs generic over trait

Hi folks, apologies for the silly confusion about a question that might have been asked many times before, but here we go.

I'm trying to create a vector containing many objects of a struct I call Handler, this handler is generic over D where D is a trait I call Detokenize. Here's the minimally reproducible code:

trait Detokenize {
    fn do_it();
}

impl Detokenize for u64 {
    fn do_it() {}
}

impl Detokenize for bool {
    fn do_it() {}
}

struct Handler<D> {
    value: D,
}

impl<D: std::fmt::Debug + Detokenize> Handler<D> {
    fn new(param: D) -> Self {
        Self { value: param }
    }

    fn get_value(&self) {
        println!("my value: {:?}", self.value);
    }
}


fn main() {
    let handler_1 = Handler::new(42 as u64);
    let handler_2 = Handler::new(10 as u64);

    // let handler_2 = Handler::new(true);
    
    handler_1.get_value();
    handler_2.get_value();
    
    let handlers = vec![handler_1, handler_2];
}

This code, as-is, works. But if I comment the first handler_2 and uncomment the second handler_2, meaning that Handler<D> will be a Handler<bool>, it complains about trying to store a Handler<u64> and Handler<bool> in the same vector, which is understandable.

My question is: what's the most idiomatic way to achieve this?

Thanks in advance.

Edit: playground link: Rust Playground

Depending on how representative the mockup is, perhaps use an enum for your Detokenize + Debug types.

The main alternative is some sort of type erasure. For that to work here, you would need to add &self parameters to your Detokenize trait methods, implement Detokenize and Debug for Box<dyn Detokenize> or otherwise re-arrange your bounds on the Handler implementation. Playground example.

You could use Box<dyn Any> and downcasting, but that's probably just a more painful enum in this case.

2 Likes

This is awesome -- thank you so much!