Result

We've seen that the Option enum can be used as a return value from functions that may fail, where None can be returned to indicate failure. However, sometimes it is important to express why an operation failed. To do this we have the Result enum.

The Result<T, E> enum has two variants:

  • Ok(value) which indicates that the operation succeeded, and wraps the value returned by the operation. (value has type T)
  • Err(why), which indicates that the operation failed, and wraps why, which (hopefully) explains the cause of the failure. (why has type E)
mod checked {
    use core::num::traits::Sqrt;

    // Mathematical "errors" we want to catch
    #[derive(Drop, Debug)]
    enum MathError {
        DivisionByZero,
        NegativeSquareRoot,
    }

    type MathResult = Result<u32, MathError>;

    pub fn div(x: u32, y: u32) -> MathResult {
        if y == 0 {
            // This operation would `fail`, instead let's return the reason of
            // the failure wrapped in `Err`
            Err(MathError::DivisionByZero)
        } else {
            // This operation is valid, return the result wrapped in `Ok`
            Ok(x / y)
        }
    }

    pub fn sqrt(x: u32) -> MathResult {
        match x {
            0 => Ok(0),
            _ => Ok(x.sqrt().into()),
        }
    }
}

// `op(x, y)` === `sqrt(x / y)`
pub fn op(x: u32, y: u32) -> u32 {
    // This is a two level match pyramid!
    match checked::div(x, y) {
        Err(why) => panic!("{:?}", why),
        Ok(ratio) => match checked::sqrt(ratio) {
            Err(why) => panic!("{:?}", why),
            Ok(sqrt) => sqrt,
        },
    }
}

pub fn main() {
    // Will this fail?
    println!("{}", op(1, 10));
}