Rustコトハジメ

プログラミング言語Rustに関する情報をお届けします。

Into implemented from From but not the opposite

From trait and Into trait are traits that takes an ownership of a object to make another object. They are not implicitly used by the compiler like Deref trait but widely exploited to write more generalized code as like AsRef trait. In Programming Rust, before these traits came in, there are lot of adhoc definitions with the same functionality.

pub trait From<T>: Sized {
    fn from(_: T) -> Self;
}

pub trait Into<T>: Sized {
    fn into(self) -> T;
}

It seems natural to me that if there is a impl From<S> for T then impl Into<T> for S is automatically defined because they are both conversion from S to T. It is actually however Into is automatically defined from From but this is not true for the opposite.

Read the document

Let's read the document of Into first.

std::convert::Into - Rust

  • Library authors should not directly implement this trait, but should prefer implementing the From trait, which offers greater flexibility and provides an equivalent Into implementation for free, thanks to a blanket implementation in the standard library.
  • There is one exception to implementing Into, and it's kind of esoteric. If the destination type is not part of the current crate, and it uses a generic variable, then you can't implement From directly.
  • This won't always allow the conversion: for example, try! and ? always use From. However, in most cases, people use Into to do the conversions, and this will allow that.
  • In almost all cases, you should try to implement From, then fall back to Into if From can't be implemented.

The blanket implementation said above is like this

// From implies Into
impl<T, U> Into<U> for T where U: From<T>
{
    fn into(self) -> U {
        U::from(self)
    }
}

Discussion

The reason behind this is that the library chose blanket implementation impl Into for From rather than impl From for Into because it is more nice to have. Let's imagine your writing a code for your type T then you want to write impl From<Other> for T for your type and the opposite Into implementation is not possible because the Other type is out of your crate.