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(...).