Essential Standard Traits

From and Into

The From<T> and Into<T> traits in std::convert define infallible, value-preserving conversions that consume a source value and return an owned target value.

Trait Definitions and the Blanket Implementation

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

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

// Provided by the standard library:
impl<T, U> Into<U> for T
where
    U: From<T>,
{
    fn into(self) -> U {
        U::from(self)
    }
}

Because the standard library provides a blanket impl<T, U> Into<U> for T where U: From<T>, you should always implement From<T> for your types rather than Into<U>. Implementing From<T> automatically gives callers both Target::from(source) and source.into().

Also, every type trivially implements From<Self> via the reflexive blanket implementation impl<T> From<T> for T.

Implementing From<T>

#[derive(Debug)]
struct Milliseconds(u64);

#[derive(Debug)]
struct Seconds(u64);

impl From<Seconds> for Milliseconds {
    fn from(sec: Seconds) -> Self {
        Milliseconds(sec.0 * 1_000)
    }
}

fn main() {
    // Explicit conversion via From::from:
    let t1 = Milliseconds::from(Seconds(3));

    // Type-inferred conversion via Into::into (provided automatically):
    let t2: Milliseconds = Seconds(12).into();

    println!("t1 = {t1:?}, t2 = {t2:?}");
}
t1 = Milliseconds(3000), t2 = Milliseconds(12000)

Generic Function Bounds with impl Into<T>

While types implement From, generic functions that accept flexible inputs take impl Into<T> as a parameter so callers can pass either T directly (via impl<T> From<T> for T) or any type convertible into T:

struct Route {
    path: String,
}

impl Route {
    fn new(path: impl Into<String>) -> Self {
        Self { path: path.into() }
    }
}

fn main() {
    // Pass a &str (converts via String::from(&str)):
    let r1 = Route::new("/api/v1/health");

    // Pass an already-owned String (zero-cost identity conversion):
    let r2 = Route::new(String::from("/api/v1/users"));

    println!("Routes: {}, {}", r1.path, r2.path);
}
Routes: /api/v1/health, /api/v1/users

Error Conversion in the ? Operator

The ? operator uses From::from implicitly to convert an inner error E1 into the enclosing function's error type E2 whenever E2: From<E1>. Implementing From<std::io::Error> for a custom application error enum allows ? to propagate io::Error seamlessly without .map_err(...).