Generic type to concrete type

Hi everyone!

I'm new to Rust and I'm trying to wrap my head around all the new paradigms.

Right now I'm stuck with the following:

Let's say we have the following struct and a method with a generic type:

pub struct Builder {
    byteBuffer: Vec<u8>,
}
impl Builder {
    fn append<T>(&self, value: Value<T>) -> Result {
    }
}

Depending on the type passed to the function I need to make decisions. Like checking and comparing the value. When done the value should be added to the buffer.

Now from what I've learned It's not that easy to get the concrete type from a generic type.
I could work with any:

let value = value.get_value() as &dyn Any;
match value.downcast_ref::<i8>() {
    Some(as_i8) => {
        if as_i8 < &-6i8 || as_i8 > &9i8 {
        ...
        ...

that seems to work but it doesn't feel right and looks quite ugly. Additionally I've read that any should be avoided if possible.

Another Option would be to implement get_value() for every concrete type needed:

impl Value<i8> {
    pub fn get_value(&self) -> &i8 {
        &self.get_value()
    }
}

For that I would need to implement the append method for every concrete type as well, which would get very verbose quite fast.

The third and last option I can think of is a trait with an implementation for every type needed which gets a reference to the buffer as parameter. The type appends itself.

I didn't try that yet but this feels like quite a lot of redundant code to me.

What would be the best way to solve this in Rust?

Thanks for your help!

Cheers

1 Like

Using a trait is the standard solution to this.

Your idea of implementing get_value four the concrete types you need won't work, because append is defined for all T. You will need to restrict T to only those types that implement the functionality you want. That's what traits are for. In this case, you could use Display or Serialize, or, if those are to permissive for your needs, implement your own trait. Alternatively, you could make Value an enum, and then it wouldn't be generic at all.

enum Value {
 I8(I8),
 U32(u32),
}

impl Value {
  fn get_value(& self) -> Vec<u8> {...}
}
1 Like

Great! Thanks for the explanation. It's sometimes quite hard to get rid of old habits.

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