Conversion Traits
Conversion traits like From↗, Into↗, TryFrom↗, and TryInto↗ enable type-safe transformations between types. From is the most common trait for defining conversions - it is implemented on the destination type and lets you create an instance from another type. Into is automatically implemented when From is, allowing values to be converted with .into(). For fallible conversions,TryFrom and TryInto return a Result, adding error handling when the conversion might fail.
Convert between Types with From
The From↗ trait defines how one type can be turned into another. Implementing From<T> for the target type allow you to write conversions like let x: Target = Target::from(source);.
Since From is infallible by design, conversions must never fail. From enables automatic Into↗ implementations, so types implementing From can be seamlessly used with .into():
#[derive(Debug)] struct Millimeters(u32); #[derive(Debug)] struct Meters(u32); impl From<Meters> for Millimeters { fn from(m: Meters) -> Self { Millimeters(m.0 * 1000) } } fn main() { let m = Meters(2); let mm: Millimeters = m.into(); println!("{mm:?}"); assert_eq!(mm.0, 2000); // OR: let m = Meters(4); let mm = Millimeters::from(m); println!("{mm:?}"); assert_eq!(mm.0, 4000); }
From↗ is often used to convert custom errors. You may also use the anyhow↗ and thiserror↗ crates.
//! Converting Custom Errors. use std::io; #[derive(Debug)] enum MyError { Io(io::Error), Message(String), } impl From<io::Error> for MyError { fn from(err: io::Error) -> Self { MyError::Io(err) } } impl From<&str> for MyError { fn from(msg: &str) -> Self { MyError::Message(msg.to_string()) } } fn main() -> Result<(), MyError> { let _file = std::fs::File::open("missing.txt")?; // `io::Error` becomes `MyError`. Err("custom failure")?; // `&str` becomes `MyError`. Ok(()) }
From may also be used when parsing. To parse strings, implement std::str::FromStr↗ instead.
//! Parsing from raw bytes. #[derive(Debug)] struct Message(String); // Implement `From` to convert from a `u8` slice to our custom struct. impl From<&[u8]> for Message { fn from(bytes: &[u8]) -> Self { Message(String::from_utf8_lossy(bytes).into()) } } fn main() { let raw: &[u8] = b"Hello world"; let msg: Message = raw.into(); // Use `From<&[u8]>`. println!("{msg:?}"); }
Choose the Right Trait for a Conversion
Paraphrasing the std::convert↗ module documentation, you should:
- Implement the
From↗ trait for explicit, infallible, consuming value-to-value conversions.Fromcreates new owned values and automatically implementsInto.Fromis the only trait here that changes ownership and produces a new value, while the others below borrow existing ones.- Implement the
Into↗ trait for consuming value-to-value conversions to types outside the current crate.
- Use
TryFrom↗/TryInto↗ when a conversion might fail. TheTryFromandTryIntotraits behave likeFromandIntootherwise. - Use
AsRef↗ /AsMut↗ when passing around references without consuming.AsReflends a borrowed view into another type without transferring ownership.- Implement the
AsReftrait for explicit, cheap reference-to-reference conversions. - Implement the
AsMuttrait for explicit, cheap mutable-reference-to-mutable-reference conversions.
- Implement the
Distinguish the above traits from the following:
FromStr↗ provides string parsing with idiomatic error handling, and it's typically implemented for types likeu32↗,Url, and enumerations. It powers.parse::<T>()↗. It can only parse types that do not contain a lifetime parameter.Deref↗ provides implicit access to the inner data of smart pointers via dereferencing (*,.method calls) - e.g., fromBox<T>toT. It is a key part of Rust's deref coercion system.Borrow↗ enables structural borrowing, especially for collections.Borrowis most often used in standard library collections likeHashMapto let you use a borrowed key (e.g.,&str) to look up an owned key (String). UnlikeAsRef, which is for conversion,Borrowimplies full equivalence in behavior. In particular,Eq,OrdandHashmust be equivalent for borrowed and owned values.
Related Topics
- AsRef.
- Borrow.
- Smart Pointers.
- String Parsing.
- Traits.