Does Rust implement From<Vec<T>> for Vec<U> if I have already implemented From<T> for U?
Asked Answered
P

3

8

I have a struct NotificationOption and another struct NotificationOption2 as well as an implementation for From<NotificationOption> for NotificationOption2.

I'm would like to convert Vec<NotificationOption> to a Vec<NotificationOption2>:

struct NotificationOption {
    key: String,
}

struct NotificationOption2 {
    key: String,
}

impl From<NotificationOption> for NotificationOption2 {
    fn from(n: NotificationOption) -> Self {
        Self {
            key: n.key,
        }
    }
}

let options: Vec<NotificationOption> = ...;
let options2: Vec<NotificationOption2> = options.into();

But I get a compiler error:

error[E0277]: the trait bound `Vec<NotificationOption2>: From<Vec<NotificationOption>>` is not satisfied
  --> src/main.rs:22:46
   |
22 |     let options2: Vec<NotificationOption2> = options.into();
   |                                              ^^^^^^^ ---- required by a bound introduced by this call
   |                                              |
   |                                              the trait `From<Vec<NotificationOption>>` is not implemented for `Vec<NotificationOption2>`

Playground link

Phytobiology answered 16/12, 2020 at 18:23 Comment(0)
T
5

It doesn't, but it's trivial to implement yourself:

let options2: Vec<NotificationOption2> = options.into_iter().map(|x| x.into()).collect();
Tartaric answered 16/12, 2020 at 19:12 Comment(0)
D
1

Seems not, and it makes sense - you assume that the conversion from Vec<NotificationOption> to Vec<NotificationOption2> is to create a Vec<NotificationOption2>, convert the NotificationOption items into NotificationOption2 using .into() and add them to the vector. Rust has no reason to assume this is the conversion and not some other routine.

You also can't implement From generically for a Vec to Vec since your crate didn't define From. You can perhaps create a conversion trait of your own, and implement it generically between Vec<X: Into<Y>> and Vec<Y>.

Dryden answered 16/12, 2020 at 19:3 Comment(6)
But the conversion that OP describes is the simplest one that doesn't drop elements. I think that is reason enough to call it the canonical one.Mancini
If Rust automagically provides this conversion, it disallows developers to write their custom conversions.Dryden
You can suggest it in an RFC but i doubt it'll gain supportDryden
@MAHanin - You can't write your own anyway, because of the orphan rule. PlaygroundMancini
what about From<Option<T>> for Option<U> ? seems like a lot of boiler plate for repitition no?Phytobiology
You can always write a generic helper function to help you conduct such conversions, saving you the boilerplates. Or a macro maybe. It isn't as nice as having it implemented via trait, but it is something. I do see the temptation in implementing all these conversions in the standard library, I just think it may be rejected on grounds of purity. But I do encourage you to try and RFC it, so wiser people will consider it and comment.Dryden
G
0

In case someone needs this as I did, here is the generic solution I came to:

pub trait VecInto<D> {
  fn vec_into(self) -> Vec<D>;
}

impl<E, D> VecInto<D> for Vec<E>
where
  D: From<E>,
{
  fn vec_into(self) -> Vec<D> {
    self.into_iter().map(std::convert::Into::into).collect()
  }
}

Then given:

struct A {
  // ...
}

struct B {
  // ...
}

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

It allows to write:

let a: Vec<A> = ...;

let b: Vec<B> = a.vec_into();

And when type inference is not possible that way, there is still this possibility:

let b = VecInto::<B>::vec_into(a);

See it working in the playground

Genuflect answered 23/4 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.