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.From
creates new owned values and automatically implementsInto
.From
is 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. TheTryFrom
andTryInto
traits behave likeFrom
andInto
otherwise. - Use
AsRef
/AsMut
when passing around references without consuming.AsRef
lends a borrowed view into another type without transferring ownership.
Distinguish the above traits from the following:
FromStr
↗ provides string parsing with idiomatic error handling, and it's typically implemented for types likeu32
,Url
, andenum
s. 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.Borrow
is most often used in standard library collections likeHashMap
to let you use a borrowed key (e.g.,&str
) to look up an owned key (String
). UnlikeAsRef
, which is for conversion,Borrow
implies full equivalence in behavior. In particular,Eq
,Ord
andHash
must be equivalent for borrowed and owned values.
Related Topics
- AsRef.
- Borrow.
- Smart Pointers.
- String Parsing.
- Traits.