Resultmap

前の例のmultiplyでのパニックは実用コードのために作られていません。 普通、呼び出し元にエラーを返し、エラー処理を呼び出し元に任せます。

まず、どのようなタイプのエラーがあるのか知る必要があります。Errの型を決めるため、 FromStrトレイトをi32に実装することで提供されているparse() 関数を見てみます。すると、Errの型はParseIntErrorだと 定義されていることがわかります。

以下の例では、愚直にmatch文を使っていますが、これは面倒です。

use std::num::ParseIntError;

// 返り値の型を書き直し、`unwrap()`を使わずパターンマッチしています。
fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
    match first_number_str.parse::<i32>() {
        Ok(first_number)  => {
            match second_number_str.parse::<i32>() {
                Ok(second_number)  => {
                    Ok(first_number * second_number)
                },
                Err(e) => Err(e),
            }
        },
        Err(e) => Err(e),
    }
}

fn print(result: Result<i32, ParseIntError>) {
    match result {
        Ok(n)  => println!("n is {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    // これはまだ使えます。
    let twenty = multiply("10", "2");
    print(twenty);

    // これは有用なエラーメッセージを返すようになりました。
    let tt = multiply("t", "2");
    print(tt);
}

幸運なことに、Optionmapand_thenなどのコンビネータはResultにも 実装されています。Resultに完全な一覧があります。

use std::num::ParseIntError;

// `Option`のように、`map()`コンビネータが使えます。
// この関数は上と同じ動作をします。
// 値が有効な場合nを渡し、その他の場合はエラーを渡す。
fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
    first_number_str.parse::<i32>().and_then(|first_number| {
        second_number_str.parse::<i32>().map(|second_number| first_number * second_number)
    })
}

fn print(result: Result<i32, ParseIntError>) {
    match result {
        Ok(n)  => println!("n is {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    // これはまだ使えます。
    let twenty = multiply("10", "2");
    print(twenty);

    // これは有用なエラーメッセージを返すようになりました。
    let tt = multiply("t", "2");
    print(tt);
}