TryFrom and TryInto
The TryFrom<T> and TryInto<T> traits in std::convert define fallible value conversions that consume a source value and return Result<Self, Self::Error>.
Trait Definitions
pub trait TryFrom<T>: Sized {
type Error;
fn try_from(value: T) -> Result<Self, Self::Error>;
}
pub trait TryInto<T>: Sized {
type Error;
fn try_into(self) -> Result<T, Self::Error>;
}
Just like From and Into, the standard library provides a blanket implementation of TryInto<U> for every type T where U: TryFrom<T>. Implement TryFrom<T> on your target type, and TryInto<U> is provided automatically.
Additionally, any type that implements infallible From<T> automatically implements TryFrom<T, Error = std::convert::Infallible>.
Checked Integer Narrowing with TryFrom
Unlike the as operator, which silently truncates out-of-range integers, standard integer types implement TryFrom for all other integer types and return Err(TryFromIntError) when the value does not fit in the target range:
fn main() {
let valid: Result<u8, _> = u8::try_from(200_i32);
let overflow: Result<u8, _> = 300_i32.try_into();
let negative: Result<u8, _> = (-5_i32).try_into();
println!("200 -> u8: {valid:?}");
println!("300 -> u8: {overflow:?}");
println!("-5 -> u8: {negative:?}");
}
200 -> u8: Ok(200)
300 -> u8: Err(TryFromIntError(()))
-5 -> u8: Err(TryFromIntError(()))
Implementing TryFrom for Domain Validation
Use TryFrom to enforce domain invariants at construction time so invalid states cannot be represented:
#[derive(Debug)]
struct NonZeroPort(u16);
#[derive(Debug)]
enum PortError {
ZeroNotAllowed,
OutOfRange(i64),
}
impl TryFrom<i64> for NonZeroPort {
type Error = PortError;
fn try_from(raw: i64) -> Result<Self, Self::Error> {
let port = u16::try_from(raw).map_err(|_| PortError::OutOfRange(raw))?;
if port == 0 {
return Err(PortError::ZeroNotAllowed);
}
Ok(NonZeroPort(port))
}
}
fn main() {
for candidate in [443, 0, 70_000] {
println!("{candidate:>6} -> {:?}", NonZeroPort::try_from(candidate));
}
}
443 -> Ok(NonZeroPort(443))
0 -> Err(ZeroNotAllowed)
70000 -> Err(OutOfRange(70000))
From vs. TryFrom
| Trait | Can Fail? | Return Type | Typical Use Case |
|---|---|---|---|
From<T> |
No | Self |
Widening (u16 to u64), wrapping (&str to String), error wrapping |
TryFrom<T> |
Yes | Result<Self, Self::Error> |
Narrowing (i64 to u8), parsing/validation, converting raw wire values to enums |