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.

列挙型Result<T, E>は2つの値をとりえます。

  • Ok(value) ... これはオペレーションが成功したことを意味し、返り値valueをラップします。(valueは型Tを持ちます。)
  • Err(why) ... これはオペレーションの失敗を意味します。whyをラップしており、ここには失敗した理由が(必ずではありませんが)書かれています。(whyの型はEです。)
mod checked {
    // 捕捉対象としたい、数学的な「エラー」
    #[derive(Debug)]
    pub enum MathError {
        DivisionByZero,
        NonPositiveLogarithm,
        NegativeSquareRoot,
    }

    pub type MathResult = Result<f64, MathError>;

    pub fn div(x: f64, y: f64) -> MathResult {
        if y == 0.0 {
            // 分母が0なので、このオペレーションは普通に行えば失敗します。
            // 代わりに`Err`でラップされた失敗の理由を返しましょう。
            Err(MathError::DivisionByZero)
        } else {
            // このオペレーションは問題がないので、
            // 結果を`Ok`でラップして返しましょう。
            Ok(x / y)
        }
    }

    pub fn sqrt(x: f64) -> MathResult {
        if x < 0.0 {
            Err(MathError::NegativeSquareRoot)
        } else {
            Ok(x.sqrt())
        }
    }

    pub fn ln(x: f64) -> MathResult {
        if x <= 0.0 {
            Err(MathError::NonPositiveLogarithm)
        } else {
            Ok(x.ln())
        }
    }
}

// `op(x, y)` === `sqrt(ln(x / y))`
fn op(x: f64, y: f64) -> f64 {
    // 3段階の`match`ピラミッド!
    match checked::div(x, y) {
        Err(why) => panic!("{:?}", why),
        Ok(ratio) => match checked::ln(ratio) {
            Err(why) => panic!("{:?}", why),
            Ok(ln) => match checked::sqrt(ln) {
                Err(why) => panic!("{:?}", why),
                Ok(sqrt) => sqrt,
            },
        },
    }
}

fn main() {
    // これは失敗するでしょうか?
    println!("{}", op(1.0, 10.0));
}