# パターン

パターンは値の形を記述し、その部分に変数を束縛します。パターンは Rust のものですが、形の種類が少なくなっています。パターンが現れる場所:

| 場所 | 反駁不能である必要 |
| ---- | ------------------ |
| `let pat = value;` | あり |
| 関数とクロージャの引数 | あり |
| `for pat in iterable` | あり |
| `match` のアーム | なし |
| `if let pat = value`、`while let pat = value` | なし |

## パターンの形 {#pattern-forms}

| パターン | 例 | 一致するもの |
| -------- | -- | ------------ |
| ワイルドカード | `_` | 何にでも一致し、何も束縛しません |
| 束縛 | `x`、`mut x` | 何にでも一致し、それを `x` に束縛します |
| リテラル | `0`、`-1`、`true`、`"Mio"`、`0.5` | リテラルと等しい値 |
| 範囲 | `3..=5`、`0..10`、`6..`、`..=2` | 範囲内の整数 |
| パス | `Route::None`、`ORIGIN`、`Self::EMPTY` | ユニットバリアント、ユニット構造体、定数 |
| タプル | `(a, _, true)`、`(first, ..)` | タプルを要素ごとに |
| タプル構造体 / バリアント | `Some(x)`、`EntityId(id)`、`Pair(a, ..)` | タプル構造体またはタプルバリアントをフィールドごとに |
| 構造体 / 構造体バリアント | `Point { x, y: 0 }`、`Shape::Rect { w, .. }` | 構造体または構造体形式のバリアントをフィールド名で |
| 代替 | `Map::A \| Map::B`、`\| 1 \| 2` | いずれかの代替に一致するもの |
| 括弧 | `(Some(_) \| None)` | 内側のパターン |

スライスや配列のパターン（`[a, b]`）、参照パターン（`&x`）、`ref` や `ref mut` の束縛、`name @ pattern` の束縛はありません。

### 束縛 {#bindings}

識別子パターンは新しい変数を束縛します。ただし、その名前がスコープ内のユニット構造体、ユニットバリアント、定数に解決される場合は、その値と比較するパスパターンになります。これは Rust と同じです。

```kis
const LIMIT: u32 = 3;

const fn at_limit(n: u32) -> bool {
    match n {
        LIMIT => true,   // the constant `LIMIT`, not a new binding
        _ => false,
    }
}
```

`mut x` は束縛を可変にします。1 つのパターンで同じ名前を 2 回束縛すると `E1024` です。代替パターン `A | B` では、すべての代替が同じ名前を束縛しなければなりません（`E1025`）。`static` はパターンに使えません（`E2035`）。

`&T` や `&mut T` 型の値を束縛以外のパターンと照合すると、参照を通り抜けて照合し、内側の束縛は部分への参照（`&T` または `&mut T`）を束縛します。Rust のデフォルト束縛モードと同じです。

### リテラルパターン {#literal-patterns}

整数リテラルは照合する型に収まらなければならず（`E2013`）、負の値も書けます。文字列リテラルは `Text` に、小数リテラルは `Decimal` に、`true` と `false` は `bool` に一致します。照合する値と異なる型のリテラルは `E2001` です。

### 範囲パターン {#range-patterns}

```kis
match AFFECTION_MIO {
    0 => MioIgnores(),
    1..=2 => MioShrugs(),
    3.. => MioSmiles(),
}
```

| 形 | 一致するもの |
| -- | ------------ |
| `a..=b` | `a` から `b` まで（両端を含む） |
| `a..b` | `a` から `b` まで（`b` を含まない） |
| `a..` | `a` 以上 |
| `..=b` | `b` 以下 |

端は整数リテラル（負も可）か、整数定数へのパスです。範囲パターンは整数（Rust 整数と `Int<lo, hi>`）にだけ一致し、それ以外の型に使うと `E2001` です。`..b` というパターンはありません。`..` 単独は下記の残余パターンです。

### 残余パターン {#rest-patterns}

タプル、タプル構造体、構造体のパターンの中の `..` は、書かれていないすべてのフィールドを表します: `(first, ..)`、`Pair(a, ..)`、`Shape::Rect { w, .. }`。タプルやタプル構造体のパターンでは 1 回だけ、任意の位置に書けます。`(.., last)` は最後の要素に一致します。構造体パターンでは最後に書きます。

### 構造体パターン {#struct-patterns}

`Point { x, y: 0 }` は `y` が 0 の `Point` に一致し、`x` を束縛します。単独で書いたフィールド（`x`、`mut x`）は同名の変数を束縛し、`field: pattern` はフィールドをパターンと照合します。書かれていないフィールドは何にでも一致します。Rust と異なり末尾の `..` は省略できますが、省略を明示するために書くこともできます。未知のフィールドは `E2020` です。形の合わないパターン（構造体バリアントにタプルパターンを使う、タプルパターンのフィールド数が違う、バリアントの代わりに enum 名を書く）は `E2035` です。

## `match` と網羅性 {#match-and-exhaustiveness}

```kix
match (VISITED_A, VISITED_B) {
    (true, true) => FestivalEnd(),
    (true, false) | (false, true) => s!(t!["One more stall."]),
    (false, false) => {}
}
```

`match` のアームは `pattern => expression` で、ガードを付けて `pattern if condition => expression` とも書けます。アームは順に試され、パターンが一致しガードが真である最初のアームが実行されます。アームはカンマで区切りますが、本体がブロックのアームの後ではカンマを省略できます。

`match` は**網羅的**でなければなりません。検査対象の型のすべての値が、いずれかのアームに一致する必要があります（`E2037`）。メッセージにはどのアームにも一致しない値が示されます。前のアームですでに網羅されていて決して実行されないアームは警告です（`W2039`）。

コンパイラーが値を把握している型:

| 型 | 検査が把握する値 |
| -- | ---------------- |
| `bool` | `true`、`false` |
| `Int<lo, hi>` | ちょうど `lo` から `hi` まで。`Int<0, 2>` は `_` なしで `0`、`1`、`2` によって網羅されます |
| Rust 整数 | 型の全範囲。`u8` の `match` には `255` までのアームか `_` が必要です |
| enum | バリアント。フィールドの中まで再帰的に |
| 構造体、タプル、配列 | 1 つの形。フィールドの中まで再帰的に |
| `&T`、`&mut T` | `T` の値 |
| `Text`、`String`、`Decimal`、`Rat`、ジェネリクスパラメーター、その他のビルトイン型 | 無制限。リテラルはそれ自身しか網羅しないので、`_` か束縛のアームが必要です |

ガードは考慮されません。ガード付きのアームは検査上何も網羅しません。パターンとして使った定数は、初期化子がリテラル、コンストラクター、またはそれらのタプルや構造体であれば、その値を網羅します。そうでなければその定数自身だけを網羅します。

`choice!{…}` の[選択肢](./forms.md#choice)は普通の enum 値なので、それに対する `match` も他と同じく検査されます。選択肢にアームがないバリアントも、処理するか `_` で網羅しなければなりません。

## 反駁可能性 {#refutability}

型のすべての値に一致するパターンを**反駁不能**といいます。`let`、`for`、引数のパターンは反駁不能でなければなりません（`E2038`）。

```kis
let (a, b) = pair;          // irrefutable
let Point { x, .. } = p;    // irrefutable
let Some(v) = maybe;        // E2038: `None` is not covered
```

反駁可能なパターンには `if let` か `match` を使います。

```kis
if let Some(v) = maybe {
    use_value(v);
}
```

`let … else` はなく、`if let` を `&&` で他の条件と組み合わせることもできません。
