Jimmy Chu
Jimmy Chu

Reputation: 982

Type mismatch: expected type parameter `N`, found struct `Vec<u8>`

I summarised my Rust code as followed:

struct Answer<N> {
    ans: N
}

trait Trait {
    fn func1<N: AsRef<[u8]>>(&self, param1: &[N]) -> Answer<N>;
}

struct MyStruct {}

impl Trait for MyStruct {
    fn func1<N: AsRef<[u8]>>(&self, param1: &[N]) -> Answer<N> {
        
        // This way we prevent bounding additional `Clone` trait on N,
        //   and not do `let ans = param1[0].clone()`
        let ans_ref: &[u8] = param1[0].as_ref();
        let mut ans: Vec<u8> = vec![0; ans_ref.len()];
        ans[..].clone_from_slice(ans_ref);
        
        Answer { ans }
    }
}

fn main() {}

Rust Playground

It returns error:

error[E0308]: mismatched types
  --> src/main.rs:20:18
   |
12 |     fn func1<N: AsRef<[u8]>>(&self, param1: &[N]) -> Answer<N> {
   |              - this type parameter
...
20 |         Answer { ans }
   |                  ^^^ expected type parameter `N`, found struct `Vec`
   |
   = note: expected type parameter `N`
                      found struct `Vec<u8>`

My question is if I do have Vec<u8> after some processing inside func1, is there any way to "typecast" Vec<u8> back to N: AsRef<[u8]>, as Vec<u8> implements AsRef<[u8]>?

Thanks.

Upvotes: 0

Views: 505

Answers (2)

Jimmy Chu
Jimmy Chu

Reputation: 982

@wayofthepie, @Stargateur (saw your suggestion in the rust playground) thanks for both the suggestions; and @wayofthepie thanks for understanding my question.

Eventually my colleague also offers an alternative solution which I think is simpler.

struct Answer<N> {
    ans: N,
}

trait Trait {
    fn func1<N: AsRef<[u8]> + From<Vec<u8>>>(param1: &[N]) -> Answer<N>;
}

struct MyStruct {}

impl Trait for MyStruct {
    fn func1<N: AsRef<[u8]> + From<Vec<u8>>>(param1: &[N]) -> Answer<N> {
        // some computation here and get the desired ans in vector of byte.
        let ans: Vec<u8> = b"abc".to_vec();
        Answer { ans: ans.into() }
    }
}

fn main() {}

Adding a From<Vec<u8>> trait bound here. Eventually ans inside Answer needs to be in the type of N, not Vec<u8>, so we need to convert it to N.

Upvotes: 0

wayofthepie
wayofthepie

Reputation: 596

In your example you are saying "I want param1 to be a slice of N". Someone can pass &[String::from("whatever")] to func1 and then N will be of type String. Your return type is Answer<N> so in this case N should be a String but you are trying to return a Vec<u8>. The caller is able to choose the type of N so you can't just return any other type. So to answer your direct question, it's not possible to do this.

In this case to make it work you can change Answer's ans field to be Box<dyn AsRef<[u8]>>, for example:

struct Answer {
    ans: Box<dyn AsRef<[u8]>>,
} 

trait Trait {
    fn func1<N: AsRef<[u8]>>(&self, param1: &[N]) -> Answer;
}

struct MyStruct {}

impl Trait for MyStruct {
    fn func1<N: AsRef<[u8]>>(&self, param1: &[N]) -> Answer {
        // This way we prevent bounding additional `Clone` trait on N,
        //   and not do `let ans = param1[0].clone()`
        let ans_ref: &[u8] = param1[0].as_ref();
        let mut ans: Vec<u8> = vec![0; ans_ref.len()];
        ans[..].clone_from_slice(ans_ref);
        Answer { ans: Box::new(ans) }
    }
}

fn main() {
    // we can pass a Vec of String, as String has an AsRef<[u8]> impl
    let params = vec![String::from("test")];
    let my_struct = MyStruct {};
    my_struct.func1(&params);

    // we can also pass a Vec of Vec
    let params = vec![vec![1, 2, 3, 4]];
    let my_struct = MyStruct {};
    my_struct.func1(&params);
}

Upvotes: 1

Related Questions