(DAY19) 俺と学ぶRust言語~Result~

# 今日の内容
- Result

# はじめに
[前回](https://qiita.com/FUKAch/items/03e47db64ab072dd33ef)はOptionについて学びました。
今回は、**Result** について学びます。

# Resultとは
`Result<T, E>`は、Rustにおけるエラーハンドリングのための列挙型です。処理の結果が「Ok」か「Err」かを表現します。
- Ok(T): 成功した場合に返す値を格納する
- Err(E): 失敗した場合に返すエラーを格納する

これにより、Rustは例外(try-catch)の代わりに、コンパイル時にエラーを明確に扱うことができます。

### Resultの定義
Result型は次のように定義されています。
標準ライブラリに用意されています。
```rust
enum Result<T, E> {
    Ok(T),
    Err(E),
}
```
- T: 成功時の値の型
- E: エラー時の情報の型

# Resultの基本的な使い方
### 1.基本例
次の例では、整数の割り算を行い、ゼロ除算が発生した場合にエラーメッセージを返す関数を定義しています。
```rust
fn divide(a:i32, b:i32) -> Result<i32, String> {
    if b == 0 {
        Err("cannot divide by zero!".to_string())
    } else {
        Ok(a / b)
    }
}

fn main() {
    match divide(10, 2) {
        Ok(result) => println!("{} / {} = {}", 10, 2, result),
        Err(e) => println!("{}", e),
    }
    match divide(10, 0) {
        Ok(result) => println!("{} / {} = {}", 10, 0, result),
        Err(e) => println!("{}", e),
    }
}
/******** 実行結果 ********
10 / 2 = 5
cannot divide by zero!
*************************/
```

### 2.Resultの値を取り出す方法
1. match構文で取り出す
    Optionと同様、match構文を使って値を取り出せます
    ```rust
    fn main() {
    let result: Result<i32, &str> = Ok(42);
    match result {
            Ok(value) => println!("成功: {}", value),
            Err(err) => println!("エラー: {}", err),
        }
    }
    /******** 実行結果 ********
    成功: 42
    *************************/
    ```
1. unwrap
    unwrapはErrの場合にプログラムをクラッシュさせます
    安全性を損なうため、基本的には避けるべきです
    ```rust
    fn main() {
        let result: Result<i32, &str> = Ok(42);
        println!("{}", result.unwrap());
    }
    /******** 実行結果 ********
    42
    *************************/
    ```
1. unwrap_or
    Errの場合に指定したデフォルト値を返します
    ```rust
    fn main() {
        let result: Result<i32, &str> = Err("エラー");
        println!("{}", result.unwrap_or(0));
    }
    /******** 実行結果 ********
    0
    *************************/
    ```
1. unwrap_or_else
    クロージャを使ってデフォルト値を計算できます
    ```rust
    fn main() {
        let result: Result<i32, &str> = Err("エラー");
        let value = result.unwrap_or_else(|e| {
            println!("エラー内容: {}", e);  
            -1  // デフォルト値
        });
        println!("{}", value);
    }
    /******** 実行結果 ********
    エラー内容: エラー
    -1
    *************************/
    ```

### よく使う便利なメソッド
1. is_okとis_err
    ResultがOkかErrかを判定します
    ```rust
    let success: Result<i32, &str> = Ok(42);
    let failure: Result<i32, &str> = Err("エラー");
    
    println!("{}", success.is_ok());//true
    println!("{}", failure.is_err());//true
    ```
1. map
    Okの値を変換します
    ```rust
    let result: Result<i32, &str> = Ok(10);
    let doubled = result.map(|x| x * 2);
    println!("{:?}", doubled);//Ok(20)
    ```
1. and_then
    Okの場合にさらに別のResultを返す処理を行います
    ```rust
    fn to_even(x: i32) -> Result<i32, &'static str>{
        if x % 2 == 0 {
            Ok(x)
        } else {
            Err("奇数です")
        }
    }
    fn main() {
        let result = Ok(4).and_then(to_even);
        println!("{:?}", result);
        let result = Ok(3).and_then(to_even);
        println!("{:?}", result);
    }
    /******** 実行結果 ********
    Ok(4)
    Err("奇数です")
    *************************/
    ```
1. or_else
    Errの場合に別の処理を実行します
    ```rust
    fn main() {
        let result:Result<i32, &str> = Err("エラー");
        let recovered: Result<i32, &str> = result.or_else(|e| {
            println!("復帰処理: {}", e);
            Ok(0)
        });
        println!("{:?}", recovered);
    }
    /******** 実行結果 ********
    復帰処理: エラー
    Ok(0)
    *************************/
    ```
1. ?
    Resultを扱う際の簡略記法
    Okなら値を返し、Errなら関数を早期終了します
    ```rust
    fn read_file(file_path: &str) -> Result<String, std::io::Error> {
        let content = std::fs::read_to_string(file_path)?;
        Ok(content)
    }
    fn main() {
        let content = read_file("test.txt");
        println!("{}", content.unwrap());
    }
    ```

# OptionとResultの違い
前回学んだOptionとResultは似ていますが、異なる機能です。以下の表に示しました。
| 特徴     | Option                           | Result              |
|:---------|:---------------------------------|:--------------------|
| 目的     | 値が「存在するか」「しないか」を表現 | 成功かエラーかを表現 |
| 列挙子   | Some/None                         | Ok/Err             |
| 主な用途 | 任意の値                           | エラーハンドリング   |

# おわりに
今回はResultについて学びました。
次回は、OptionとResultを組み合わせたエラーハンドリングの応用について学んでいきます。
ご精読、ありがとうございました。