Hi! I recently tried to write some code like this:
struct Foo {}
struct Error1 {}
struct Error2 {}
impl From<Error1> for Error2 {
fn from(other: Error1) -> Self {
Error2 {}
}
}
fn main() {
let v1: Vec<Result<Foo, Error1>> = vec![];
let r1: Result<Vec<Foo>, Error2> = v1.into_iter().map(|r| r.map_err(|e| e.into())).collect();
let v2: Vec<Result<Foo, Error1>> = vec![];
let r2: Result<Vec<Foo>, Error2> = v2.into_iter().collect();
}
Since the ?
operator does error conversion automatically in cases like this when Error2: From<Error1>
, I expected that the .collect()
method would also figure out that r2
can be computed like r1
, but this turned out not to be the case:
error[E0277]: a collection of type `std::result::Result<std::vec::Vec<Foo>, Error2>` cannot be built from an iterator over elements of type `std::result::Result<Foo, Error1>`
= help: the trait `std::iter::FromIterator<std::result::Result<Foo, Error1>>` is not implemented for `std::result::Result<std::vec::Vec<Foo>, Error2>`
I tried implementing this in the standard libraries, and it turns out it can be done quite easily, although it does break some type inference since the output type becomes more ambiguous. In short, what I did was to change this:
impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E>
to this:
impl<A, E1, E2: From<E1>, V: FromIterator<A>> FromIterator<Result<A, E1>> for Result<V, E2>
Has this been considered before? Does it seem like a good idea?