Result

Resultは値の不在エラーに置き換えたOption型 の上位互換です。

つまり、Result<T, E>は2つの結果を持つことができます。

  • Ok(T): Tが存在する場合
  • Err(E): Eというエラーが見つかった場合

利便性のため、期待する値をOk、予期せぬ値をErrに入れます。

Optionと同じように、Resultは多くのメソッドを持っています。例えば、 unwrap()T型の値を返すか、panicします。また、条件処理のために、 Optionと同じようなコンビネータがResultにもあります。

Rustを使っていると、おそらく、parse()のようにResult型を返す ようなメソッドに出会うでしょう。文字列をいつも他の型に変換できるとは限らない ため、parse()は失敗を処理するためにResultを使っています。

成功した場合と失敗した場合の文字列のparse()の振る舞いを見てみましょう。

fn multiply(first_number_str: &str, second_number_str: &str) -> i32 {
    // `unwrap()`を使って数値を取り出してみましょう。
    let first_number = first_number_str.parse::<i32>().unwrap();
    let second_number = second_number_str.parse::<i32>().unwrap();
    first_number * second_number
}

fn main() {
    let twenty = multiply("10", "2");
    println!("double is {}", twenty);

    let tt = multiply("t", "2");
    println!("double is {}", tt);
}

parse()が失敗した場合は、unwrap()panicを起こしてプログラムを終了しました。 さらに、panicは不快なエラーメッセージを返しました。

エラーメッセージの質を改善するため、返り値の型をさらに特定し、明示的に エラーを処理する必要があります。

mainResultを使う

明示的に指定することで、Result型をmain関数で使うこともできます。 典型的なmain関数はこのような形です。

fn main() {
    println!("Hello World!");
}

しかし、mainは返り値としてResultを使うこともできます。main関数内でエラーが 起これば、エラーコードを返し、デバッグプリントでエラーを報告します。(Debug トレイトを使います。) 以下の例では、次の例では、そのようなシナリオを紹介し、 後の節で扱う内容にも触れます。

use std::num::ParseIntError;

fn main() -> Result<(), ParseIntError> {
    let number_str = "10";
    let number = match number_str.parse::<i32>() {
        Ok(number)  => number,
        Err(e) => return Err(e),
    };
    println!("{}", number);
    Ok(())
}