RustでOption値やResult値を上手に扱う

## この記事の概要

`Option<T>` 型や `Result<T, E>` 型の戻り値を、`match` 式で判別している以下のようなコードを、

```rust
fn double_arg(mut argv: env::Args) -> Result<i32, String> {
    match argv.nth(1) {
        None => Err("数字を１つ指定してください。".to_owned()),
        Some(arg1) => {
            match arg1.parse::<i32>() {
                Ok(n) => Ok(2 * n),
                Err(err) => Err(err.to_string()),
            }
        }
    }
}
```

Rust の標準的な部品を組み合わせて、以下のように、すっきり読みやすく仕上げるまでの道のりを紹介します。

```rust
fn double_arg(mut argv: env::Args) -> Result<i32, CliError> {
    let arg1 = try!(argv.nth(1).ok_or(CliError::NotEnoughArgs));
    let n = try!(arg1.parse::<i32>());
    Ok(2 * n)
}
```

なお、この記事は、Rust の公式ドキュメント「Rustプログラミング言語」（日本語翻訳版）の [エラーハンドリング](https://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/error-handling.html) の章を参考にして書きました。


### Rust のバージョン

この記事のコードは、2016年2月現在の最新の安定版で動作確認済みです：

- rustc 1.6.0
- cargo 0.8.0 (08da2f5 2015-12-21)

rustc 1.0 以降なら、どのバージョンでも問題なく動くと思います。


### ソースコード

本記事で紹介するソースコードは、GitHub に置いてあります。

- [tatsuya6502/rust-option-result-examples](https://github.com/tatsuya6502/rust-option-result-examples)

Rust と Cargo がインストールされた環境で、以下のようにすれば実行できます。

```shell-session
$ cd rust-option-result-examples
$ cargo --bin main{1-7の連番} -- プログラムへの引数
```

例：

```shell-session
$ cargo --bin main7 -- 123
   Compiling error-handling v0.1.0 (file:/// ... rust-option-result-examples)
     Running `target/debug/main7 123`
246
```


## 基礎知識：`Option<T>` 型と `Result<T, E>` 型

### `Option<T>` 型

Rust の [`Option<T>` 型](https://doc.rust-lang.org/std/option/enum.Option.html)は、値が **存在しない** 可能性を暗示する列挙型です。定義は以下の通りです。

```rust
enum Option<T> {
    None,
    Some(T),
}
```

T型の値が存在する時は、`Some` で包まれています。存在しない時は `None` になります。

`Option` 型は、他の言語では `Maybe` や `Optional` などと呼ばれることもあります。

**例：**

Linux の Docker が使える環境で [rusti](http://qiita.com/tatsuya6502/items/61af3f4d6c52e472f899) を実行：

```shell-session
% sudo docker run -it --rm quay.io/tatsuya6502/rusti
# cd ~/rusti
# cargo run
rusti=>
```

`Some(10)` は `Option<i32>` 型です。

```rust
rusti=> Some(10)
Some(10)
rusti=> .type Some(10)
Some(10) = core::option::Option<i32>
```

注意： rusti で型を見ると `core` ライブラリの `Option<T>` 型が優先されてしまいます。通常の Rust プログラムでは `core` ライブラリを `use` 指定してないので、`core` ではなく、`std` ライブラリの `std::option::Option<T>` 型になります。

こちらは `Option<String>` 型です。

```rust
rusti=> Some("Hello, world!".to_owned())
Some("Hello, world!")
rusti=> .type Some("Hello, world!".to_owned())
...省略... = core::option::Option<collections::string::String>
```

`None` は単体だと `Option<T>` の `T` が決まらないので、コンパイルエラーになります。

```rust
rusti=> None
<anon>:13:20: 13:24 error: unable to infer enough type information about `_`; type annotations or generic parameter binding required [E0282]
...
```

ヒントを与えましょう。

```rust
rusti=> None as Option<i32>
None
rusti=> .type None as Option<i32>
... = core::option::Option<i32>
```

`Some` に包まれた値を取り出すには、`match` 式による場合分けをします。

```rust
rusti=> .block
rusti+> let v = Some(10);
rusti+> match v {
rusti+>     Some(n) => n,
rusti+>     None    => -1,
rusti+> }
rusti+> .
10
```

`Option` に出会う度に場合分けをするのは面倒なので、標準ライブラリでは、`Option` から値を取り出したり、加工したりするためのメソッドが用意されています。例えば `unwrap()` は最も素朴なメソッドで、以下のような定義になっています：

```rust:Option&lt;T&gt;のunwrap()の定義
impl<T> Option<T> {
    fn unwrap(self) -> T {
        match self {
            Option::Some(val) => val,
            Option::None =>
              panic!("called `Option::unwrap()` on a `None` value"),
        }
    }
}
```

このように `Some<T>` に適用すると、値が取り出せます。

```rust
rusti=> Some(10).unwrap()
10
```

そして、`None` に適用すると、パニックします。

```rust
rusti=> (None as Option<i32>).unwrap()
thread '<main>' panicked at 'called `Option::unwrap()` on a `None` value', ../src/libcore/option.rs:330
```

`map()` はクロージャを引数にとり、`Some` の中の値にクロージャを適用して、結果を `Some` で包み直します。もし `None` に適用すると、`None` を返します。

```rust
rusti=> Some(10).map(|n| 2 * n)
Some(20)
rusti=> (None as Option<i32>).map(|n| 2 * n)
None
```

`and_then()` は `map()` に似ていますが、違いは `Some<T>` だけでなく `None` も返せることです。

```rust
rusti=> Some(10).and_then(|n| if n > 5 {Some(n)} else {None} )
Some(10)
rusti=> Some(5).and_then(|n| if n > 5 {Some(n)} else {None} )
None
rusti=> (None as Option<i32>).and_then(|n| if n > 5 {Some(n)} else {None} )
None
```

`map()` や `and_then()` は入力と出力に `Option<T>` 型の値を１つだけ取るので、数珠つなぎにできます。このような性質を持つメソッドを、コンビネータと呼びます。

```rust
rusti=> Some(10).and_then(|n| if n > 5 {Some(n)} else {None}).map(|n| 2 * n)
Some(20)
rusti=> Some(5).and_then(|n| if n > 5 {Some(n)} else {None}).map(|n| 2 * n)
None
```


### `Result<T, E>` 型

Rust の [`Result<T, E>` 型](https://doc.rust-lang.org/std/result/enum.Result.html)は **エラーになる可能性** を暗示する列挙型です。定義は以下の通りです。

```rust
enum Result<T, E> {
    Ok(T),
    Err(E),
}
```

処理が成功した時は値を `Ok` で包みます。失敗した時はエラーの値を `Err` で包みます。

`Result` 型は、他の言語では `Either` と呼ばれることもあります。

```rust
rusti=> .type Ok(10) as Result<i32, ()>
... = core::result::Result<i32, ()>
rusti=> .type Ok("Success!".to_owned()) as Result<String, ()>
... = core::result::Result<collections::string::String, ()>
rusti=> .type Err("Not found".to_owned()) as Result<i32, String>
... = core::result::Result<i32, collections::string::String>
```

`Option<T>` と同じようなメソッドが用意されています。`unwrap()` は値が `Err` の時はパニックします。

```rust
rusti=> (Ok(10) as Result<i32, String>).unwrap()
10
rusti=> (Err("Not found".to_owned()) as Result<i32, String>).unwrap()
thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: "Not found"', ../src/libcore/result.rs:746
```

`and_then()` や `map()` は、値が `Ok<T>` のときはクロージャを実行し、値が `Err<E>` のときほ元の値を未加工で返します。

```rust
rusti=> .block
rusti+> (Ok(10) as Result<i32, String>)
rusti+>   .and_then(|n| if n > 5 {Ok(n)} else {Err("Too small".to_owned())})
rusti+>   .map(|n| 2 * n)
rusti+> .
Ok(20)
```

```rust
rusti=> .block
rusti+> (Ok(5) as Result<i32, String>)
rusti+>   .and_then(|n| if n > 5 {Ok(n)} else {Err("Too small".to_owned())})
rusti+>   .map(|n| 2 * n)
rusti+> .
Err("Too small")
```

また、逆に値が `Err` のときだけ働くメソッドもあります。

```rust
rusti=> .block
rusti+> (Err("Not found".to_owned()) as Result<i32, String>)
rusti+>   .map_err(|e| "Error! ".to_owned() + &e)
rusti+> .
Err("Error! Not found")
```


## 明示的な場合分けから、`try!` マクロとコンビネータへ

では、冒頭にあげたプログラムを例に、`Option<T>` や `Result<T, E>` の扱いを、少しずつ改善していきましょう。このプログラムは、コマンドライン引数として整数値を表す文字列を受け取り、それを２倍した値を表示します。

**引数として `"10"` を与えた時：**

```shell-session
% cargo run --bin main1 -- 10
     Running `target/debug/main1 10`
20
```


### `unwrap()` を使う

まず最初は、エラーの可能性は考慮せず、正しい引数が渡されたときの機能だけを実装します。以下のように `double_arg()` 関数は、コマンドライン引数の１番目の値を取得して、整数値としてパースし、２倍して返します。

```rust:src/main1.rs
use std::env;

fn double_arg(mut argv: env::Args) -> i32 {
    let arg1 = argv.nth(1).unwrap(); // エラー1
    let n = arg1.parse::<i32>().unwrap(); // エラー2
    2 * n
}
```

そして呼び出し元となる `main()` 関数では、`double_arg()` を呼び出して、結果を表示するようにしました。

```rust:src/main1.rs
fn main() {
    let n = double_arg(env::args());
    println!("{}", n);
}
```

このプログラムは、正しい引数を与えれば問題なく動きます。

```shell-session
% cargo run --bin main1 -- 42
     Running `target/debug/main1 42`
84
```

しかし当然、エラーになるとパニックを起こしてクラッシュします。

まず、引数を指定しないと、先ほどのソースコードのエラー１の行でパニックします。

```shell-session
% cargo run --bin main1
     Running `target/debug/main1`
thread '<main>' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:367
Process didn't exit successfully: `target/debug/main1` (exit code: 101)
```

メッセージの意味は、`None` に対して、`Option::unwrap()` が呼ばれました、です。`argv.nth(1)` は `Option<String>` 型の値を返します。コマンドライン引数のインデックス１の文字列があれば `Some` が返され、なければ `None` を返します。

```rust
rusti=> use std::env;
rusti=> .type env::args().nth(1)
... = core::option::Option<collections::string::String>
```

また、引数が整数としてパースできないときも、エラー２の行でパニックします。

```shell-session
% cargo run --bin main1 -- hoge
     Running `target/debug/main1 hoge`
thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }', src/libcore/result.rs:741
Process didn't exit successfully: `target/debug/main1 hoge` (exit code: 101)
```

メッセージの意味は、`Err` に対して、`Result::unwrap()` が呼ばれました、です。`parse()` は、（この場合は `i32` 型の結果が期待されていますので） `Result<i32, std::num::ParseIntError>` 型の値を返します。パースできれば `Ok<i32>` を、できなければ `Err<std::num::ParseIntError>` を返します。

```rust
rusti=> .type "10".parse::<i32>()
... = core::result::Result<i32, core::num::ParseIntError>
```


### 明示的な場合分けをする

では、この２つのエラーに対応できるようにしましょう。`double_arg()` 関数は `unwrap()` でパニックする代わりに、エラーが起こったことを、戻り値を使って呼び出し元（`main()` 関数）に伝えるようにします。リターン型が `i32` のままだとエラーを表現できないので、`Result<i32, String>` に変更します。エラーの内容は `String` 型の文字列で渡します。

まずは素朴なやり方として、`match` 式によるパターンマッチ、つまり、明示的な場合分けをしましょう。

```rust:src/main2.rs
use std::env;

fn double_arg(mut argv: env::Args) -> Result<i32, String> {
    match argv.nth(1) {
        None => Err("数字を１つ指定してください。".to_owned()),
        Some(arg1) => {
            match arg1.parse::<i32>() {
                Ok(n) => Ok(2 * n),
                Err(err) => Err(err.to_string()),
            }
        }
    }
}
```

このように、もし `argv.nth(1)` が `None` を返したら、「数字を１つ指定してください」という `String` 型の文字列を `Err()` で包んで返します。

またもし `parse::<i32>()` が `Err<std::num::ParseIntError>` を返したら、`ParseIntError` を `to_string()` で `String` 型の文字列に変換してから、`Err<String>` で包んで返します。

エラーがなければ、数値を２倍した値を `Ok<i32>` 型で返します。

`main()` 関数は `double_arg()` 関数からの戻り値に対して `match` 式で場合分けをして、必要ならエラーメッセージを表示します。

```rust:src/main2.rs
fn main() {
    match double_arg(env::args()) {
        Ok(n) => println!("{}", n),
        Err(err) => println!("エラー：{}", err),
    }
}

```

試してみましょう。

**引数を忘れた時：**

```shell-sesison
% cargo run --bin main2
     Running `target/debug/main2`
エラー：数字を１つ指定してください。
```

**引数が整数としてパースできない時：**

```
% cargo run --bin main2 -- hoge
     Running `target/debug/main2 hoge`
エラー：invalid digit found in string
```

どちらのケースもパニックしなくなりました。後者のメッセージは英語ですが、期待通りに動いてます。

この方法の長所は、プログラムの内容が見たままで、なにも抽象化されていないので、初心者にとってわかりやすいことです。短所は、エラーケースの場合分けが増えてくると、正常ケースのロジックがそれに埋もれてしまい、分かりにくくなってしまうことです。

最初はこのような書き方でもかまわないと思いますが、Rust に慣れてきたら、この後紹介するコンビネータや `try!` マクロを使った方法へ移行していくことをお勧めします。


### コンビネータを使う

明示的な場合分けを、コンビネータに肩代わりしてもらいましょう。このように書き換えられます。

```rust:src/main3.rs
use std::env;

fn double_arg(mut argv: env::Args) -> Result<i32, String> {
    argv.nth(1)
        .ok_or("数字を１つ指定してください。".to_owned())
        .and_then(|arg1| arg1.parse::<i32>().map_err(|err| err.to_string()))
        .map(|n| 2 * n)
}

fn main() {
  // main2.rs と同じ。省略
}
```

`Option<T>` の `ok_or()` コンビネータは、`argv.nth(1)` が返した `Option<T>` 型の値を、`Result<T, E>` 型に変換してくれます。もし値が `Some<T>` なら `Ok<T>` を作ります。もし値が `None` なら `Err<E>` を作って、引数として渡した値（この場合は `String` 型の `"数字を１つ指定してください。"`）を包みます。

```rust
rusti=> Some("10").ok_or("error!".to_owned())
Ok("10")
rusti=> (None as Option<i32>).ok_or("error!".to_owned())
Err("error!")
```

`Result<T, E>` の `and_then()`、`map_err()`、`map()` コンビネータは先ほど紹介した通りです。

流れを追ってみましょう。

**コマンドライン引数に `"10"` が与えられたとき：**

0. `argv.nth(1)` が `Some("10")` を返す。
0. `ok_or()` コンビネータが、`Ok("10")` に変換する。
0. `and_then()` コンビネータが、`Ok<String>` の中の値 `"10"` を取り出し、クロージャに渡す。
0. クロージャは `"10"` に `arg1.parse::<i32>()` を適用して、`Ok(10)` が得られる。
0. 同クロージャの `map_err()` コンビネータは何もせず、`Ok(10)` を返す。
0. `map()` コンビネータは `Ok(10)` の中の値 `10` を取り出して、クロージャに渡す。
0. クロージャはそれを２倍して `20` を返す。
0. `map()` コンビネータは、それを包み直して `Ok(20)` を返す。この値が `double_arg()` の戻り値になる。

**コマンドライン引数が与えられなかったとき：**

0. `argv.nth(1)` は `None` を返す。
0. `ok_or()` コンビネータは `Err<String>` 型の値 `Err("数字を１つ...")` を返す。
0. 後続の `and_then()` と `map()` は何もせず、`Err<String>` 値をそのまま返す。（`double_arg()` の戻り値）

**コマンドライン引数に、数値として無効な値 `"hoge"` が与えられたとき：**

0. `and_then()` コンビネータのクロージャで `"hoge".parse::<i32>()` が実行され `Err<std::num::ParseIntError>` 型の値が返る。
0. `map_err()` コンビネータがエラーの値に `to_string()` を適用して、`Err<String>` 型の値が作られる。
0. `map()` コンビネータは何もせず、`Err<String>` 値をそのまま返す。（`double_arg()` の戻り値）

どうでしょう？　たしかに行数は少なくなりましたし、プログラムの文面は英語の文章っぽくなりました。しかし、クロージャが頻出するので個人的には、少し読みにくくなったように思えます。慣れの問題かもしれませんが。

次の `try!` マクロとコンビネータを組み合わせる方法を見てみましょう。


### `try!` マクロとコンビネータを組み合わせる

Rust らしいやり方は、`try!` マクロとコンビネータを適度に組み合わせることです。`try!()` マクロは、コンビネータと同様に場合分けを肩代わりしてくれます。しかし、それだけでなく「早期リターン(early return)」という、制御フローの抽象化もしてくれます。

```rust:src/main4.rs

use std::env;

fn double_arg(mut argv: env::Args) -> Result<i32, String> {
    let arg1 = try!(argv.nth(1).ok_or("数字を１つ指定してください。".to_owned()));
    let n = try!(arg1.parse::<i32>().map_err(|err| err.to_string()));
    Ok(2 * n)
}

fn main() {
  // main2.rs と同じ。省略
}
```

`try!()` マクロは、`Result<T, E>` 型の値を返す式を取ります。式を評価して `Ok<T>` の値が得られた時は、`unwrap()` のように、中の値を取り出して返します。一方、`Err<E>` の値が得られた時は、`return` 文を使って `double_arg()` 関数から抜け出して、呼び出し元（`main()`）にそのエラーの値を返します。

流れを追ってみましょう。

**コマンドライン引数として `"10"` が与えられたとき：**

0. `argv.nth(1)` が `Some("10")` を返す。
0. `ok_or()` コンビネータが、`Ok("10")` に変換する。
0. `try!()` マクロが中の値 `"10"` を取り出す。
0. 変数 `arg1` が `"10"` に束縛される。
0. `"10"` に `parse::<i32>()` を適用すると `Ok(10)` が得られる。
0. `map_err()` コンビネータは、`Ok(10)` をそのまま返す。
0. `try!()` マクロは `Ok(10)` の中の値 `10` を取り出す。
0. 変数 `n` が`10` に束縛される。
0. `2 * n` の結果を `Ok<i32>` に格納する。（`double_arg()` の戻り値）

**コマンドライン引数が与えられなかったとき：**

0. `argv.nth(1)` が `None` を返す。
0. `ok_or()` コンビネータは `Err<String>` 型の値 `Err("数字を１つ...")` を返す。
0. `try!()` マクロは `return Err("数字を１つ...");` を実行し、`main()` 関数へ早期リターンする。

**コマンドライン引数に、数値として無効な値 `"hoge"` が与えられたとき：**

0. 変数 `arg1` が `"10"` に束縛されるところまでは、正常系と同じ。
0. `"hoge".parse::<i32>()` が `Err<std::num::ParseIntError>` 型の値を返す。
0. `map_err()` コンビネータがエラーの値に `to_string()` を適用して、`Err<String>` 型の値が作られる。
0. `try!()` マクロが `return ...` を実行し、`main()` 関数へ早期リターンする。

早期リターンという手法が加わったことで、コードがすっきりしたと思いませんか？　エラー処理をしてなかった頃のコードと比較してみましょう。

**エラー処理なし**

```rust:src/main1.rs
fn double_arg(mut argv: env::Args) -> i32 {
    let arg1 = argv.nth(1).unwrap(); // エラー1
    let n = arg1.parse::<i32>().unwrap(); // エラー2
    2 * n
}
```

**エラー処理あり**

```rust:src/main4.rs
fn double_arg(mut argv: env::Args) -> Result<i32, String> {
    let arg1 = try!(argv.nth(1).ok_or("数字を１つ指定してください。".to_owned()));
    let n = try!(arg1.parse::<i32>().map_err(|err| err.to_string()));
    Ok(2 * n)
}
```

エラー処理を加えた後でも、コードの明快さは失われてません。正常ケースのロジックがはっきりとわかりますし、その一方で、どこでエラーが起こりうるか、また、エラーが起こったらどうするのかもわかります。


## エラー情報を改善する

いままで `double_arg()` ではエラーが起こった時に `Err<String>` 型の値を返していました。これは手軽な方法ですし、今回のような短いプログラムでは十分、実用に耐えられます。でも残念なのは、`parse::<i32>()` がせっかく `Err<std::num::ParseIntError>` 型の値を返しているのに、それを文字列に変換してから返していることです。

いったんエラーが文字列に変換されてしまうと、呼び出し元では場合分けがしにくくなってしまいます。例えば呼び出し元の `main()` 関数で、引数が指定されなかった時と、数値として無効な値が与えられた時で、別の動作をさせたくなったらどうしますか？また、エラーメッセージを日本語にローカライズしたい時もやりにくいでしょう。

もし `double_arg()` が `Err<std::num::ParseIntError>` のようにエラーの値をそのまま返すなら、この問題は解決します。


### `Box<Error>` 型を返す

エラーの値を直接返したいと思った時に問題になるのは、`double_arg()` では２種類のエラーが起こる可能性があることです。一方は `Err<std::num::ParseIntError>` ですが、もう一方はコマンドライン引数がなかった時に `None` になるので、いまは `Err<String>` 型の値を作って返しています。このままでは、両者を一つにまとめられないないので、リターン型の `Result<i32, 何かのエラー型>` の `何かのエラー型` の部分を決められません。

`ParseIntError` は、`std::error::Error` トレイトを実装しています。そこで、コマンドライン引数がなかった時のエラー型を新たに定義して、同じように `Error` トレイトを実装しましょう。こうすれば、両者を一つにまとめられます。

`NotEnoughArgsError` という構造体を作ります。

```rust:src/main5.rs
use std::error;
use std::fmt;

#[derive(Debug)]
struct NotEnoughArgError {}
```

このように `Debug` トレイトの実装を自動導出（derive）しています。`Error` トレイトを実装する時は `Debug` トレイトの実装が必須なので、自動導出するのがいいでしょう。

さらに、`std::fmt::Display` トレイトが要求する `fmt()` 関数の実装も必要です。

```rust:src/main5.rs
impl fmt::Display for NotEnoughArgError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "引数が不足しています")
    }
}
```

最後に `std::error::Error` トレイトが要求する `description()` 関数と `cause` 関数を実装します。

```rust:src/main4.rs
impl error::Error for NotEnoughArgError {
    fn description(&self) -> &str {
        "引数が不足しています"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}
```

これで `NotEnoughArgsError` の実装は OK です。

さて、`double_arg()` のリターン型を変更して `Result<i32, error::Error>` にしたいところですが、これは Rust ではできません。Rust では関数の戻り値に、トレイトを使うことができないのです。

なぜなら、Rustは関数の引数と戻り値をコールスタックに直接積みますが、そのためには、コンパイル時に、これらの値が必要とするメモリのサイズが決まってないといけないのです。型を `Error` にしてしまうと、`Error` トレイトを実装している型ならどんなものでもスタックに置けることになります。しかし、個々の具象型（将来実装されるものも含む）によって、必要とするメモリのサイズが異なるので、それらをコンパイル時に列挙して、サイズを予測することは不可能です。

これを解決する方法のひとつはトレイトオブジェクトを使うことです。これは、元のエラー値を `Box` で包むことで作れます。具体的には `Box::new(エラー値)` とします。

```rust
rusti=> .type Box::new("hoge".parse::<i32>().unwrap_err())
... = Box<core::num::ParseIntError>
rusti=> .type Box::new("hoge".parse::<i32>().unwrap_err()) as Box<std::error::Error>
... = Box<std::error::Error>
```

値を box 化すると、その実体はスタックではなくて、ヒープに格納されるようになります。そしてスタックには、その実体へのポインタが積まれます。ポインタなら、必要なメモリサイズがコンパイル時に決まりますので大丈夫なわけです。

`double_arg()` のリターン型を `Result<i32, Box<error::Error>>` に変更します。

```rust:src/main5.rs（続き）

use std::env;
use std::error;

fn double_arg(mut argv: env::Args) -> Result<i32, Box<error::Error>> {
    let number_str = try!(argv.nth(1).ok_or(NotEnoughArgsError));
    let n = try!(number_str.parse::<i32>());
    Ok(2 * n)
}

fn main() {
  // main2.rs と同じ。省略
}
```

これで OK です。

あれ？でも、`Err<NotEnoughArgError>` や `Err<num::ParseIntError>` 型の値を `try!()` に渡しているのに、リターン型として `Result<i32, Box<error::Error>>` と書けるのは不思議に思いませんか？さっき、box 化するには `Box::new(エラー値)` とすると言ったばかりです。なぜ、それがなくてもコンパイルできるのでしょう。

種を明かすと `try!()` マクロがエラーの型を変換しています。`try!()` マクロは以下のように定義されています。

```rust
macro_rules! try {
    ($e:expr) => (match $e {
        Ok(val) => val,
        Err(err) => return Err(::std::convert::From::from(err)),
    });
}
```

単に `Err<なにかの型>` の値を返すのではなく、そこに格納されたエラーの値に `std::convert::From` トレイトの `from()` を適用してから、`Err<E>` で包み直しています。この `from()` 関数は、ある型の値を、別の型の値へ変換します。そして、標準ライブラリには、以下のような `From` 実装があります。

```rust
impl<'a, E: Error + 'a> From<E> for Box<Error + 'a>
```

この実装により、`Error` トレイトを実装した全ての型の値は、トレイトオブジェクト `Box<Error>` へ変換できるのです。

つまり `try!()` マクロは、以下の３つを抽象化しています。

1. 場合分け
2. 制御フロー
3. エラー値の型変換

`double_arg()` 関数のコードを、もう一度比較してみましょう。

**エラー処理なし（エラー時にクラッシュする）**

```rust:src/main1.rs
fn double_arg(mut argv: env::Args) -> i32 {
    let arg1 = argv.nth(1).unwrap(); // エラー1
    let n = arg1.parse::<i32>().unwrap(); // エラー2
    2 * n
}
```

**エラー処理あり**

```rust:src/main5.rs
fn double_arg(mut argv: env::Args) -> Result<i32, Box<error::Error>> {
    let arg1 = try!(argv.nth(1).ok_or(NotEnoughArgsError));
    let n = try!(arg1.parse::<i32>());
    Ok(2 * n)
}
```

`try!()` がエラーを変換してくれるので、以前の例にあった `map()` が不要になりました。フル機能のエラー処理を行っていますが、そのためのオーバーヘッド（付随するコード）は、ほとんどありません！


### `Box<Error>` の些細な問題

前の節ではトレイトオブジェクト `Box<Error>` を使いましたが、ここには些細な問題があります。`Box` で包まれた値は `Error` トレイトを実装していることまでは分かるのですが、その具象型（`NotEnoughArgError` または `ParseIntError`）がなんであったのかは、コンパイラにはわからなくなってしまうのです。このようなコンパイラーの動作を、型消去(type erasure) と呼びます。

例えば、呼び出し元の `main()` 関数の側で、エラーの種類に応じて処理を分岐させたくても、単純な場合分けでは判断できなくなります。以下のように書くことはできません。

```rust:コンパイルエラーになる
fn main() {
    match double_arg(env::args()) {
        Ok(n) => println!("{}", n),
        Err(Box(num::ParseIntError(..))) => {
            println!("不正な数字です \"{}\"", env::args().nth(1).unwrap())
        },
        Err(err) => println!("エラー：{}", err),
    }
}
```

方法はなくはありせん。実行時のリフレクションを使って、具象型へダウンキャストすることは可能です。

```rust:src/main6.rs
fn main() {
    match double_arg(env::args()) {
        Ok(n) => println!("{}", n),
        Err(err) => {
            match err.downcast_ref::<num::ParseIntError>() {
                None => println!("エラー：{}", err),
                Some(..) => println!("不正な数字です \"{}\"", env::args().nth(1).unwrap()),
            }
        }
    }
}
```

起こりうるエラーの型一つ一つについて、ダウンキャストできたかの場合分けをしていくのは、少し冗長です。

ダウンキャストしなかったとしても、`String` を返すよりは良くなっています。なぜなら、`Error` トレイトに用意された、`description()` メソッドや `cause()` メソッドで、エラーについての、より詳細な情報を取得できるからです。


### 列挙型で独自のエラー型を定義する

この記事の締めくくりとして、トレイトオブジェクトを使った時の些細な問題を解決しましょう。２種類のエラーの値を包むことができる列挙型を定義して、`Error` トレイトと `From` トレイトを実装するのです。列挙型なら、トレイトオブジェクトと違い、型消去が起こりません。

列挙型を定義しましょう。コマンドラインインターフェイス（CLI）で起こるエラーということで、名前は `CliError` としています。バリアントとして、`NotEnoughArgs` と `Parse(num::ParseIntError)` を用意します。

```rust:src/main7.rs
use std::error;
use std::fmt;
use std::num;

#[derive(Debug)]
enum CliError {
    NotEnoughArgs,
    Parse(num::ParseIntError),
}
```

`Display` トレイトと、`Error` トレイトを実装します。このように値に応じて、単純に処理を切り替えれば OK です。

```rust:src/main7.rs
impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CliError::NotEnoughArgs => write!(f, "引数が不足しています"),
            CliError::Parse(ref err) => write!(f, "Parse error: {}", err),
        }
    }
}

impl error::Error for CliError {
    fn description(&self) -> &str {
        match *self {
            CliError::NotEnoughArgs => "引数が不足しています",
            CliError::Parse(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CliError::NotEnoughArgs => None,
            CliError::Parse(ref err) => Some(err),
        }
    }
}
```

引数がなかった時のエラーは `CliError` だけで十分表現できるので、前の節で作った `NotEnhoughArgsError` は、いらなくなってしまいました。

`double_arg()` 関数を修正しましょう。

```rust:src/main7.rs
fn double_arg(mut argv: env::Args) -> Result<i32, CliError> {
    let arg1 = try!(argv.nth(1).ok_or(CliError::NotEnoughArgs));
    let n = try!(arg1.parse::<i32>().map_err(|e| CliError::Parse(e)));
    Ok(2 * n)
}
```

このように、戻り値を `Result<i32, CliError>` に変更しました。しかし、`arg1.parse::<i32>()` が `num::ParseIntError` を返したときのために、`map_err()` コンビネータによる変換が必要になってしまいました。

これを取り除くのは簡単です。`num::ParseIntError` から `CliError` への変換をする `From` トレイトを実装すればいいのです。

```rust:src/main7.rs
impl From<num::ParseIntError> for CliError {
    fn from(err: num::ParseIntError) -> CliError {
        CliError::Parse(err)
    }
}
```

`double_arg()` 関数は最終的にこうなります。

```rust:src/main7.rs
fn double_arg(mut argv: env::Args) -> Result<i32, CliError> {
    let arg1 = try!(argv.nth(1).ok_or(CliError::NotEnoughArgs));
    let n = try!(arg1.parse::<i32>());
    Ok(2 * n)
}
```

`main()` 関数は以前のままでも動きますが、せっかく列挙型を導入したので、`double_arg()` 関数の戻り値を使って、`CliError::Parse()` の時も日本語のメッセージを出すようにしましょう。

```rust:src/main7.rs
fn main() {
    match double_arg(env::args()) {
        Ok(n) => println!("{}", n),
        Err(err @ CliError::NotEnoughArgs) => println!("エラー：{}", err),
        Err(CliError::Parse(..)) => {
            println!("エラー：不正な数字です \"{}\"",
                     env::args().nth(1).unwrap())
        }
    }
}
```

これで完成です！


## まとめ

1. `Option<T>` と `Result<T, E>` のコンビネータについて、よく学んでおきましょう。これらの値を簡潔に処理するための道具が用意されています。特によく使うのは `and_then()`、`map()`、`unwrap_or()` です。
2. `try!()` マクロを使いこなしましょう。このマクロは３つのことを抽象化してくれます：
   * 場合分け
   * 制御フロー（早期リターン）
   * エラー値の型変換
3. エラー型に文字列を使うのは避けて、`Box<Error>` を使いましょう。必要に応じて、構造体によるエラー型を定義しましょう。
4. `Box<Error>` の型消去が問題になる場合は、列挙型を定義してエラーの値をラップしましょう。

３と４は必須ではありません。簡単なアプリケーションを書いている時は、`Result<T, String>` 型で十分なこともあります。

この記事で解説した内容を、もっと詳しく知りたくなったら、公式ドキュメント（日本語翻訳版）の [エラーハンドリング](https://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/error-handling.html) を読んでください。

もちろん、公式ドキュメントのそれ以外の章も、Rust を使う上で理解しておくべき内容が詰まっていますので、ぜひ読んでもらいたいです。翻訳の進捗状況と、翻訳済みページヘのリンクは [ここ](https://github.com/rust-lang-ja/the-rust-programming-language-ja/wiki/%E7%BF%BB%E8%A8%B3%E9%80%B2%E8%A1%8C%E7%8A%B6%E6%B3%81%E7%AE%A1%E7%90%86%E8%A1%A8) にあります。