Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Convert vector of type A to type B where A is convertible to B

I’m learning rust, and one of the most basic things I want to do is to take one vector of homogenous type A which is convertible to another type B (since From<> is implemented and thus we can use .into()). When I tried running the below I got the following:

struct A {
    x: String
}

struct B {
    x: String
}

impl From<A> for B {
    fn from(a: A) -> Self {
        B { x: a.x }
    }
}

impl B {
    pub fn from_many<T: Into<B> + Clone>(v: Vec<T>) -> Self {
        B { x: v.iter().map(|e| B::from(e.clone()).x).collect::<Vec<String>>().join(" ") }
    }
}

fn main() {
    ...
}

I got:

error[E0277]: the trait bound `B: From<T>` is not satisfied
  --> src/main.rs:17:41
   |
17 |         B { x: v.iter().map(|e| B::from(e.clone()).x).collect::<Vec<String>>().join(" ") }
   |                                 ------- ^^^^^^^^^ the trait `From<T>` is not implemented for `B`
   |                                 |
   |                                 required by a bound introduced by this call
   |
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
   |
15 | impl B where B: From<T> {
   |        ++++++++++++++++

I originally tried it without the clone(), but thought that it didn’t accept references:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

...
impl B {
    pub fn from_many<T: Into<B>>(v: Vec<T>) -> Self {
        B { x: v.iter().map(|e| B::from(e).x).collect::<Vec<String>>().join(" ") }
    }
}
...

which yielded:

error[E0277]: the trait bound `B: From<&T>` is not satisfied
  --> src/main.rs:17:41
   |
17 |         B { x: v.iter().map(|e| B::from(e).x).collect::<Vec<String>>().join(" ") }
   |                                 ------- ^ the trait `From<&T>` is not implemented for `B`
   |                                 |
   |                                 required by a bound introduced by this call
   |
   = help: the trait `From<A>` is implemented for `B`

I’m not asking for an arbitrary T here, I’m asking for T which has Into<B> for T defined (in this case, I believe it’s defined since I defined the From trait). Did I do something stupid here?

>Solution :

You’re missing a very simple but easy to miss fact: if you have a From<T> for U implementation you automatically have a Into<U> for T implementation, but the opposite is not true. Thus, if by generics you require T: Into<B> (which is the right thing to do since it is more generic than B: From<T>), you need to use .into() and not B::from():

impl B {
    pub fn from_many<T: Into<B> + Clone>(v: Vec<T>) -> Self {
        B { x: v.iter().map(|e| e.clone().into().x).collect::<Vec<String>>().join(" ") }
    }
}

Another, but unrelated, thing you’re missing is that since you have an owned Vec<T> you can use into_iter() and then you don’t need to .clone():

impl B {
    pub fn from_many<T: Into<B>>(v: Vec<T>) -> Self {
        B { x: v.into_iter().map(|e| e.into().x).collect::<Vec<String>>().join(" ") }
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading