rusttraits

I have extended a type with a trait, why is my Vec<impl ThatTrait> not accepting a type that implements that trait?


I have a trait Input that adds a to_custom_bytes() method to Strings and u64s.

trait Input {
    fn to_custom_bytes(&self) -> Vec<u8>;
}

impl Input for u64 {
    fn to_custom_bytes(&self) -> Vec<u8> {
        self.to_le_bytes().to_vec()
    }
}

impl Input for String {
    fn to_custom_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }
}

I have a function that takes a Vector of items that implement that trait:

fn inputs_to_custom_bytes(inputs: Vec<impl Input>) -> Vec<u8> {
    let mut bytes: Vec<u8> = Vec::new();
    for input in inputs {
        bytes.extend(input.to_custom_bytes());
    }
    bytes
}

Why does Rust compiler complain expected 'String', found 'u64' for age, when age implements this Trait and the argument is Vec<impl Input> not Vec<String>?

pub fn main() {
    let name = String::from("steve");
    let age: u64 = 20;
    let custom_bytes: Vec<u8> = inputs_to_custom_bytes(vec![name, age]);
}


Solution

  • impl in a generic parameter means one such type, so can't be used for multiple types at the same time. Thus a function accepting Vec<impl Input> can be called with a Vec<u64> or a Vec<String>, but there is no concrete type called Vec<impl Input>; that's a generic type parameter.

    dyn can be used instead of impl, for trait objects, which allow mixing multiple types of values, using runtime lookup to call the correct function at runtime. So you should be able to accomplish something similar with a Vec<&dyn Input>.

    pub fn inputs_to_custom_bytes(inputs: Vec<&dyn Input>) -> Vec<u8> {
        let mut bytes: Vec<u8> = Vec::new();
        for input in inputs {
            bytes.extend(input.to_seeds());
        }
        bytes
    }