16.4 Fallible Conversions with TryFrom and TryInto

Not all conversions are guaranteed to succeed. Rust uses the TryFrom and TryInto traits for these cases, returning Result<T, E> rather than a value that might silently overflow or otherwise fail.

16.4.1 Handling Conversion Failures

use std::convert::TryFrom;

fn main() {
    let x: i8 = 127;
    let y = u8::try_from(x);     // Ok(127)
    let z = u8::try_from(-1);    // Err(TryFromIntError(()))
    println!("{:?}, {:?}", y, z);
}

16.4.2 Implementing TryFrom and TryInto for Custom Types

You can define your own error type and logic when implementing TryFrom:

use std::convert::TryFrom;
use std::convert::TryInto;

#[derive(Debug, PartialEq)]
struct EvenNumber(i32);

impl TryFrom<i32> for EvenNumber {
    type Error = String;

    fn try_from(value: i32) -> Result<Self, Self::Error> {
        if value % 2 == 0 {
            Ok(EvenNumber(value))
        } else {
            Err(format!("{} is not an even number", value))
        }
    }
}

fn main() {
    assert_eq!(EvenNumber::try_from(8), Ok(EvenNumber(8)));
    assert_eq!(EvenNumber::try_from(5), Err(String::from("5 is not an even number")));

    let result: Result<EvenNumber, _> = 8i32.try_into();
    assert_eq!(result, Ok(EvenNumber(8)));

    let result: Result<EvenNumber, _> = 5i32.try_into();
    assert_eq!(result, Err(String::from("5 is not an even number")));
}