kovaxis
kovaxis

Reputation: 955

`T.into()` works but `From::from(T)` does not

In this following code snippet, convert is trying to convert its input to a Box<Error>:

fn convert<T: Into<Box<Error>>>(input: T) -> Box<Error> {
    input.into() // Compiles
    // From::from(input) // Fails to compile
}

It works with input.into(), but when using From::from(T) it no longer works, it requires T to implement Error:

error[E0277]: the trait bound `T: std::error::Error` is not satisfied
 --> src/main.rs:4:3
  |
4 |   From::from(input)
  |   ^^^^^^^^^^ the trait `std::error::Error` is not implemented for `T`
  |
  = help: consider adding a `where T: std::error::Error` bound
  = note: required because of the requirements on the impl of `std::convert::From<T>` for `std::boxed::Box<std::error::Error>`
  = note: required by `std::convert::From::from`

Why do the requirements change when using From or Into? This becomes specially annoying when using the ? operator:

fn convert<T: Into<Box<Error>>>(input: T) -> Result<(), Box<Error>> {
    Err(input)? // Fails to compile
}

Is there any way to use the ? operator properly in these cases, or do I have to resort to manual match and into?

Upvotes: 3

Views: 191

Answers (2)

Shepmaster
Shepmaster

Reputation: 430634

Why do the requirements change when using From or Into?

Even when something implements Into, that doesn't mean it implements From. For example, from the implementor list of Into:

impl<T, U> Into<U> for T 
where
    U: From<T>, 

impl Into<Option<P<PathParameters>>> for AngleBracketedParameterData
impl Into<Vec<Annotatable>> for Annotatable
impl<T> Into<Vec<T>> for ThinVec<T>
impl<T> Into<Vec<T>> for P<[T]>

Those last four types do not implement From, but they do implement Into. (Note that these types are actually internal compiler types and it's a bug that we can see them in the docs, but it's a useful demonstration for this case.)

See When should I implement std::convert::From vs std::convert::Into? for more details about the differences of the two traits.


You can instead declare that your generic type implements From to use it:

fn convert<T>(input: T) -> Box<Error>
where
    Box<Error>: From<T>,
{
    From::from(input) // Fails to compile
}

Upvotes: 9

Lukazoid
Lukazoid

Reputation: 19416

One solution would be to write your generics in terms of From:

fn convert<T>(input: T) -> Result<(), Box<Error>>
where
    Box<Error>: From<T>,
{
    Err(input)?
}

Upvotes: 4

Related Questions