When should I implement std::convert::From vs std::convert::Into?

TL;DR: prefer implementing From.


Interestingly, the original RFC about the std::convert traits suggested the opposite blanket implementation:

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

But on the PR implementing it, it was changed to the opposite:

Added From => Into implementation, which makes it possible to add conversions in both directions without running afoul of coherence. For example, we now have From<[T]> for Vec<T> where T: Clone, which yields the corresponding Into going in the other direction — despite the fact that the two types live in different crates.

I also believe this addresses a few concerns about things implementing From instead of Into

This last-moment change reflects that From and Into are basically equivalent. From was chosen as the preferred one as it was less restrictive from the “type parameter vs. local type” point of view.

Before Rust 1.41.0, it wasn’t possible to make a impl<'a, T> Into<Foo> for &'a [T], while impl<'a, T> From<&'a [T]> for Foo was possible.

The first attempt raised a E0210:

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
 --> x.rs:3:10
  |
3 | impl<'a, T> Into<Foo> for &'a [T] {
  |          ^ type parameter `T` must be used as the type parameter for some local type
  |
  = note: only traits defined in the current crate can be implemented for a type parameter

In the standard library prior to Rust 1.14, there were only two examples of implementing Into and not From:

  • impl Into<Vec<u8>> for String
  • impl Into<OsString> for PathBuf

I think these are the reflexion of the logic of their interfaces. OsString implements From<String> and From<T> where T: AsRef<OsStr>, because they are the natural things you’ll want to build a OsString from.

However, PathBuf still implements Into<OsString> as the reverse operation of its From<OsString> implementation, but this logic belongs to PathBuf, not OsString.

Leave a Comment