Rust TryFrom & TryInto
TryFrom and TryInto are conversion traits for conversions that can fail. A conversion returns a Result instead of a plain value.
A conversion that returns a Result
TryFrom is like From, but the conversion may fail, so it returns a Result. The standard library uses it for narrowing number changes: 300 is too big for a u8.
println!("{:?}", u8::try_from(200));
println!("{:?}", u8::try_from(300));Write your own fallible conversion
Implement TryFrom<Old> for New, and name the failure type inside as type Error:
impl TryFrom<i32> for Percentage {
type Error = String;
fn try_from(value: i32) -> Result<Self, Self::Error> {
// check the value, then return Ok(..) or Err(..)
}
}Call it with Type::try_from(value)
Percentage accepts only 0 to 100. A value in range gives Ok. A value outside gives Err with our message:
println!("{:?}", Percentage::try_from(80));
println!("{:?}", Percentage::try_from(120));try_into: the same door, the other way
Implement TryFrom and TryInto comes free. Write the target type in the Result annotation:
let r: Result<Percentage, String> = 50i32.try_into();
println!("{:?}", r);Example
#[derive(Debug, PartialEq)]
struct Percentage(i32);
impl TryFrom<i32> for Percentage {
type Error = String;
fn try_from(value: i32) -> Result<Self, Self::Error> {
if (0..=100).contains(&value) {
Ok(Percentage(value))
} else {
Err(format!("{} is not between 0 and 100", value))
}
}
}
fn main() {
println!("{:?}", Percentage::try_from(80));
println!("{:?}", Percentage::try_from(120));
let small: Result<u8, _> = 300i32.try_into();
println!("300 as u8: {:?}", small);
let ok: Result<Percentage, _> = 50i32.try_into();
println!("50 as Percentage: {:?}", ok);
}Key points
- Handle the Result with match, unwrap, or ? — exactly like any other fallible call
- TryFrom means "this might fail".
- Picking the right pair tells your reader which promise you are making.
- The number 300 fits in an i32, but it can never fit in a u8.
- Error is an associated type: a type slot the trait leaves for the impl to fill in.
In this example, Percentage accepts only numbers from 0 to 100. try_from(80) passes the check, so it returns Ok(Percentage(80)). try_from(120) fails the check, so it returns Err with our message. The third line uses a conversion from the standard library. 300 does not fit in a u8. So try_into returns an Err too. The last line runs our own conversion through try_into: 50 is in range, so the result is Ok(Percentage(50)). One impl gave us both directions.
Note
From means "this always works".
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What does u8::try_from(300) return?