[Rust]エラーハンドリング：Resultの使い方

## `Result`型

Nullableな値を扱う際に`Option`型があるというのは前記事で取り上げましたが、より具体的に「処理の成否」を格納するための型として`Result`型というものがあります。
`Result`型は内部に`Ok<T>`と`Err<E>`（`T`と`E`はどちらもジェネリクス）の２つの要素を持ちます。処理が成功したときの値は`Ok<T>`に、失敗したときのエラーは`Err<E>`に格納されます。

処理が失敗する可能性がある処理は`Result`型を返すのが一般的です。`Result`は`Option`同様に`match`によるパターンマッチングが利用できます。
```rust
fn divide(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 {
        Err("Division by zero".to_string())
    } else {
        Ok(a / b)
    }
}

fn main() {
    let result = divide(10, 2);
    match result {
        Ok(value) => println!("Result: {}", value),
        Err(error) => println!("Error: {}", error),
    }

    let result = divide(10, 0);
    match result {
        Ok(value) => println!("Result: {}", value),
        Err(error) => println!("Error: {}", error),
    }
}
```

`Ok`に値が入っているときにのみ特定の処理を行いたい場合、`and_then`メソッドが使えます。`match`を使うと、`Err`の場合のパターンも記述しなくてはならない上に、分岐が連続するとブロックがネストされて見にくくなります。このメソッドを使うことで、記述量を減らせます。

```rust
fn parse_to_number(input: &str) -> Result<i32, String> {
    input.parse::<i32>().map_err(|_| "Failed to parse number".to_string())
}

fn divide_by_two(num: i32) -> Result<i32, String> {
    if num % 2 == 0 {
        Ok(num / 2)
    } else {
        Err("Cannot divide an odd number by 2".to_string())
    }
}

fn main() {
    let result = Ok("42")
        .and_then(parse_to_number) // "42" をパースして 42 を返す
        .and_then(divide_by_two);  // 42 を 2 で割り、21 を返す

    match result {
        Ok(value) => println!("Final result: {}", value),
        Err(error) => println!("Error: {}", error),
    }
}

```
また、`Ok`に入った値をもとに新たな値を返したい場合は`map`メソッドが使えます。

```rust
fn main() {
    let result = Ok(10)
        .map(|x| x * 2)  // 成功値 10 を 20 に加工
        .map(|x| x + 5); // 20 に 5 を足して 25 に加工

    match result {
        Ok(value) => println!("Processed value: {}", value), // Processed value: 25
        Err(error) => println!("Error: {}", error),
    }
}

```

:::note
例外のthrowではなく`Result`型を返却する、というのは（筆者のにわか知識ですが）関数型プログラミングを想像させます。このタイプのプログラミングはしたことがないので非常に興味があります。エラーハンドリングを型システムで定義するというのは安全そうですね。TypeScriptにも`neverthrow`などのライブラリがあるので、いつか触ってみたいです。
:::

:::note
`and_then`も`map`も
- `Ok`が存在するときの処理を書ける
- 値を返すことができる

という共通点があります。どう使い分けるのかはいろいろアイデアがありそうですが、個人的にはこちらの記事が非常に参考になりました。
- [Rust mapとand_thenの理解](https://yabutan.com/posts/230402_rust_map_and_then_difference)

筆者の理解では、
- 複数の処理をチェーンしたい、途中で失敗する可能性がある場合→`and_then`
- 単純に値の変換だけしたい、失敗ケースは考えない場合→`map`

と使い分けるのが良さそうに思えました。
:::

### `Result`型に名前をつける

`Result`は一種の型なので、よく使うであろう`Result`型を`type`キーワードで宣言しておくと便利です。

```rust
type MyResult<T> = Result<T, String>;

fn divide(a: i32, b: i32) -> MyResult<i32> {
    if b == 0 {
        Err("Division by zero".to_string())
    } else {
        Ok(a / b)
    }
}

fn main() {
    let result: MyResult<i32> = divide(10, 2);
    println!("{:?}", result);
}
```

## Early Return

いくつかの処理を連続して実行し、それぞれの処理の成否によっては処理を中断し`Err`を返すパターンをEarly Return（早期リターン）と呼びます。
`match`式が値を返せることを利用し、`Ok`であればその値を変数にバインディングして次に進み、`Err`であれば`Err`を`return`するパターンです。

この方法であればネストは発生せず、かつ「処理Aが失敗したら全体的に失敗とするが、処理Bが失敗したらフォールバック値を使う」といった柔軟な処理が実装できます（`Result`というより、`Option`の特徴に着目しているといえます）。

```rust
fn divide(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 {
        Err("Division by zero".to_string())
    } else {
        Ok(a / b)
    }
}

fn increment_if_even(x: i32) -> Result<i32, String> {
    if x % 2 == 0 {
        Ok(x + 1)
    } else {
        Err("Not an even number".to_string())
    }
}

fn process(value: i32) -> Result<i32, String> {
    let value = match divide(value, 2) {
        Ok(v) => v,
        Err(e) => return Err(e),
    };

    let value = match increment_if_even(value) {
        Ok(v) => v,
        Err(e) => return Err(e),
    };

    Ok(value)
}

fn main() {
    match process(8) {
        Ok(result) => println!("Success: {}", result),
        Err(error) => println!("Error: {}", error),
    }
}

```

## `?`を使って安全に`Ok`の値を取り出す

「ある処理の値が`Err`であればそれを`return`する」という前提のもと、より簡潔に書けるのが`?`構文です。`Result`型を返すメソッドの後に`?`をつけると、`Err`が返されたときの`return`が不要になります（自動で行ってくれる）。

```rust
fn divide(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 {
        Err("Division by zero".to_string())
    } else {
        Ok(a / b)
    }
}

fn add_five(x: i32) -> Result<i32, String> {
    Ok(x + 5)
}

fn calculate(a: i32, b: i32) -> Result<i32, String> {
    let result = divide(a, b)?; // Okなら値を取得、Errならreturn
    add_five(result)
}

fn main() {
    match calculate(10, 2) {
        Ok(value) => println!("Final result: {}", value),
        Err(error) => println!("Error: {}", error),
    }
}
```