16.3 Safe, Infallible Conversions: From
and Into
The From<T>
and Into<U>
traits represent conversions that are guaranteed to succeed, meaning they are infallible. This contrasts with conversions that might fail, such as narrowing an integer (i32
to i8
), which are handled by the TryFrom
/TryInto
traits (covered in Section 16.4). From
/Into
are the idiomatic Rust way to express a safe and unambiguous transformation from one type to another. Crucially, for conversions where success cannot be guaranteed (like i32
to u8
), the From
trait is deliberately not implemented in the standard library. This forces the programmer to choose an alternative: either the safe, error-handling approach with TryFrom
, or an explicit, potentially lossy cast using as
.
impl From<T> for U
defines how to create aU
instance from aT
instance.- If
From<T>
is implemented forU
, the compiler automatically provides an implementation ofInto<U>
forT
. This works because the standard library includes a generic implementation conceptually similar toimpl<T, U> Into<U> for T where U: From<T> { fn into(self) -> U { U::from(self) } }
. Essentially, calling.into()
on a value of typeT
delegates the conversion to theU::from(t)
implementation.
Conversion can be invoked via U::from(value_t)
or value_t.into()
. The into()
method relies on type inference; the compiler must be able to determine the target type U
from the context (e.g., variable type annotation).
16.3.1 Standard Library Examples
The standard library provides numerous From
implementations for common, safe conversions:
fn main() { // Integer widening (always safe) let val_u8: u8 = 100; let val_i32 = i32::from(val_u8); // Explicit call to from() let val_u16: u16 = val_u8.into(); // into() infers target type from variable declaration println!("u8: {}, converted to i32: {}, converted to u16: {}", val_u8, val_i32, val_u16); // String conversions let message_slice = "Hello from slice"; let message_string = String::from(message_slice); // Canonical way to create owned String from &str let message_string_again: String = message_slice.into(); // Also works due to From<&str> for String println!("Owned string: {}", message_string); println!("Owned string (via into): {}", message_string_again); // Creating collections // Here, [1, 2, 3] is an array literal of type [i32; 3] let vec_from_array = Vec::from([1, 2, 3]); // Convert the Vec<i32> into an owned slice Box<[i32]> // Vec<T> can be converted into Box<[T]> and vice versa via From/Into. // Note: [i32] is a dynamically sized slice type; Box<[i32]> owns it. let boxed_slice: Box<[i32]> = vec_from_array.into(); println!("Boxed slice: {:?}", boxed_slice); }
16.3.2 Implementing From
for Custom Types
Implement From
to define standard, safe conversions for your own data structures:
#[derive(Debug)] struct Point3D { x: i64, y: i64, z: i64, } // Allow creating a Point3D from a tuple (i64, i64, i64) impl From<(i64, i64, i64)> for Point3D { fn from(tuple: (i64, i64, i64)) -> Self { Point3D { x: tuple.0, y: tuple.1, z: tuple.2 } } } // Allow creating a Point3D from an array [i64; 3] impl From<[i64; 3]> for Point3D { fn from(arr: [i64; 3]) -> Self { Point3D { x: arr[0], y: arr[1], z: arr[2] } } } fn main() { let p1 = Point3D::from((10, -20, 30)); let p2: Point3D = [40, 50, 60].into(); // Type inference works here println!("p1: {:?}", p1); println!("p2: {:?}", p2); }
Using From
/Into
clearly signals that the conversion is a standard, safe, and lossless transformation for the involved types.