列挙型とパターンマッチング　その2


この記事は以下の記事を翻訳して、自分なりに理解した内容をまとめています。

https://doc.rust-lang.org/book/ch06-02-match.html

# The match Control Flow Operator

Rustにはmatchという強力な制御フロー演算子がある。
matchは各パターンで値が適合すると関連する処理ブロックに分類され、実行する。
コインを使った例を示す。

```rust
enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}
```

value_in_centsではmatchキーワードの後に式（この場合はcoin値）をリストする。
if文との違いは、if文はbool値を返すが、この場合では任意の値の型にできる。
この場合はCoin列挙型である。

次はマッチアームである。
アームにはパターンと何らかのコードの2つがある。
ここでの最初のアームはcoin::Pennyであり、次におパターンと実行するコードを区切る=>演算子がある。
この場合のコードは値1である。

match式は上から順番に比較され、当てはまるパターンに関連付けられたコードが実行される。
一致しない場合は次のアームに進む。
アームは必要な数だけ持つことができる。
上の例では4つのアームがある。

各アームに関連付けられたコードは式であり、当てはまるアームの式の結果は当てはまる式全体に対して返される値である。

コードが短い式である場合は中括弧は使用されない。
コードが複数の場合は中括弧が使用できる。
例として、以下はCoin::Pennyの場合はLucky penny!と表示出力され値1を返す。

```rust
fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => {
            println!("Lucky penny!");
            1
        }
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}
```

# Patterns that Bind to Values


マッチアームのもう1つの便利な機能は、パターンに当てはまる値の部分にバインドできることである。
これは、列挙型バリアントから値を抽出する方法である。

列挙型バリアントの1つを変更して、その中にデータを保持してみる。
Quarterバリアントを変更して、その中に格納されているUsState値を含める。

```rust

#[derive(Debug)] // so we can inspect the state in a minute
enum UsState {
    Alabama,
    Alaska,
    // --snip--
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}
```

このコードでは、バリアントCoin::Quarterの値に当てはまるstateという変数をパターンに追加している。
Coin::Quarterが当てはまると、変数stateはそのquarterのstateの値にバインドされる。
次のようにそのアームのコードで状態を使用できる。

```rust

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("State quarter from {:?}!", state);
            25
        }
    }
}
```

value_in_cents(Coin::Quarter(UsState::Alaska))を呼び出す場合、coinはCoin::Quarter(UsState::Alaska)となる。
その値をmatchの各アームと比較すると、Coin::Quarter(state)に到達する。
Coin::Quarter(state)に到達するまで他のいずれにも一致せず、その時点でstateはUsState::Alaskaにバインドされる。
その後、println!でそのバインディングを使用される。

# Matching with Option\<T>

Coin列挙型でmatchを使用してOption\<T>を処理することができる。

Option\<i32>を取り、内部に値がある場合は、その値に1を追加する関数を作成する。
内部に値がない場合、関数はNone値を返し、操作を実行しないようにする必要がある。

```rust

    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            None => None,
            Some(i) => Some(i + 1),
        }
    }

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
```

plus_one(five)を呼び出すとplus_oneの本体の変数xの値はSome(5)になる。
次にそれを各matchアームと比較する。

```
None => None,
```
には一致しないので、次のアームへ進む。

```
            Some(i) => Some(i + 1),
```
Some(5)はSome(i)に当てはまるる。
iはSomeに含まれた値にバインドされるため、値5を取得する。
次にmatchアームのコードが実行されるためiの値に1が加算され、値6を含む新しいSome値を作成する。

plus_oneの2番目の呼び出しの場合、xはNoneである。

```
None => None,
```

Noneに一致し、=>の右側にあるNoneを返す。以後の比較は行わない。

# Matches Are Exhaustive

以下の場合はNoneの処理を記述していないため、コンパイルエラーになる
Oprion\<T>に対してmatchを使用する場合は必ずNoneパターンの記述が必要。

```rust

    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            Some(i) => Some(i + 1),
        }
    }
```

![スクリーンショット 2020-11-12 080311.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624329/80f15e68-087c-95d8-c61d-095384b7f15c.jpeg)

# The _ Placeholder

matchには、いずれのパターンにも一致しない場合に使用できるパターンも存在する。
以下の場合は、1,3,5,7のみを考慮し、2,4,6,8,9以降の値を考慮しない代わりにパターン_が使用できる。

```rust

    let some_u8_value = 0u8;
    match some_u8_value {
        1 => println!("one"),
        3 => println!("three"),
        5 => println!("five"),
        7 => println!("seven"),
        _ => (),
    }
```

パターン_は任意の値に当てはまる。
()は単なる単位値であるため、何も起こらない。


まぁ、いわゆるswitch構文のようなもんだな。