[Swift]caseのちょっと奥の方

# なにこれ？

前回[[Swift] caseの使い方を覚えて一段上のプログラミングを](https://qiita.com/masakihori/items/d9bd0e1bb387bb5f0166)の続きにあたります。
`case`をもうちょっと深く掘り下げてみます。

以下ではThe Swift Programming LanguageのSummary of the Grammarを引用していきます。
> この部分が引用です。



# BNF記法っぽいやつ
Summary of the Grammarを見ていきます。
まず`for`は以下のようになっています。
> for-in-statement → **for** **case**? pattern **in** expression where-clause? code-block

`for-case`の後ろに続くのは`pattern`であることが分かりました。

次に`while`、`if`および`guard`を見てみましょう。

> while-statement → **while** condition-list code-block

> if-statement → **if** condition-list code-block else-clause?

> guard-statement → **guard** condition-list **else** code-block

これらは全て`case`の後ろは`condition-list`となっています。
`condition-list`は以下の通りです。

> condition-list → condition | condition , condition-list
> condition → expression | availability-condition | case-condition | optional-binding-condition
> case-condition → **case** pattern initializer

こちらも`case`に続くものは`pattern`です。
最後に`switch`です。
> switch-statement → **switch** expression **{** switch-cases? **}**
> switch-cases → switch-case switch-cases?
> switch-case → case-label statements
> switch-case → default-label statements
> switch-case → conditional-switch-case
> case-label → attributes? **case** case-item-list :
> case-item-list → pattern where-clause? | pattern where-clause? , case-item-list

ちょっと込み入っていますが、他と同様`case`の後ろに続くものは`pattern`です。

# pattern
`case`の後ろに続くものは常に`pattern`である事が分かりました。
では`pattern`にはどのようなものはあるのかを見ていきましょう。

> pattern → wildcard-pattern type-annotation?
> pattern → identifier-pattern type-annotation?
> pattern → value-binding-pattern
> pattern → tuple-pattern type-annotation?
> pattern → enum-case-pattern
> pattern → optional-pattern
> pattern → type-casting-pattern
> pattern → expression-pattern

結構ありますね。
順番に詳しく見ていきます。

## wildcard-pattern
> pattern → wildcard-pattern type-annotation?
> wildcard-pattern → **_**

前回ちょこっと出てきた何にでもマッチする **_** です。
```swift
let value = 10

switch value {
  case 0: print("0")
  case 1: print("1")
  case _: print("other")
}
```

`type-annotation`が使えますが、あまり使いどころはないと思われます。


## identifier-pattern
> pattern → identifier-pattern type-annotation?
> identifier-pattern → identifier

`identifier`つまり変数名や関数名タイプ名などがこれに当たります。
```swift
let range = 0...10
let i = 3

if case range = i {
  print("\(i) is in 0 to 10")
}
```
などです。

## value-binding-pattern
> pattern → value-binding-pattern
> value-binding-pattern → **var** pattern | **let** pattern

これはパターンにマッチした値を取得するものです。
```swift
let value = 10

switch value {
  case let v: print("value is \(v)")
}
```
また`let`/`var`の後には`pattern`が続きますが、**どこか**に値を格納するための`identifier-pattern`を含む必要があります。

## tuple-pattern
> pattern → tuple-pattern type-annotation?
tuple-pattern → **(** tuple-pattern-element-list? **)**
tuple-pattern-element-list → tuple-pattern-element | tuple-pattern-element **,** tuple-pattern-element-list
tuple-pattern-element → pattern | identifier **:** pattern

これはそのまま、タプルを検査するものです。
```swift
let tuple = (0, "a")

switch tuple {
  case (0, "a"): print("left is 0 and right is a")
  case (0, _): print("left is zero")
  case (_, "a"): print("right is a")
  default: print("other")
}
```
**()** の中身が`pattern`であることに注意してください。

## optional-pattern
> pattern → optional-pattern
> optional-pattern → identifier-pattern ?


```swift
let optionalValue: Int? = 0
if case let wrappedValue? = a {
  print("\(wrappedValue)")
}
```
`value-binding-pattern`の`let`の後に続く`pattern`が`optional-pattern`になっています。

# type-casting-pattern
> pattern → type-casting-pattern
> type-casting-pattern → is-pattern | as-pattern
> is-pattern → **is** type
> as-pattern → pattern **as** type

特定の型の場合にマッチするパターンです。
```swift
let value: Any = 0

switch value {
  case is Int: print("Int")
  case let s as String: print("String \(s)")
  default: print("other")
}
```

# expression-pattern
> pattern → expression-pattern
> expression-pattern → expression
> いっぱいありすぎなので省略

パターンマッチ演算子（ ~= ）が利用可能なすべての**式**がこれに当てはまります。
```swift
struct S {
  var range: ClosedRange<Int> = 0...1
  
  static func ~= (l: Self, r: Int) -> Bool { l.range ~= r }
  
  func newRange() -> ClosedRange<Int> { 0..1 }
}

let value = 10
switch value {
  case ..<0: ()
  case 0: ()
  case S(): ()
  case S().range: ()
  case S().newRange(): ()
  default: ()
}
```

# ここからが本題です

## enum-case-pattern
このパターンはあえて後ろに回していました。

> pattern → enum-case-pattern
> enum-case-pattern → type-identifier? . enum-case-name tuple-pattern?

`type-identifier`はenumの型名です。省略可能です。
`enum-case-name`はenumの要素名です。
そして、そのあとに続くのが`tuple-pattern`です。
`case`においてenumの要素名の後ろに続く`()`はAssociated Valueの`()`ではなく`tuple-pattern`の`()`です。

`tuple-pattern`のGrammarを改めてみてみましょう。
> pattern → tuple-pattern type-annotation?
tuple-pattern → ( tuple-pattern-element-list? )
tuple-pattern-element-list → tuple-pattern-element | tuple-pattern-element , tuple-pattern-element-list
tuple-pattern-element → pattern | identifier : pattern

`taple-pattern`のタプルの要素部分に入るものは`pattern`です。
`pattern`であればなんでも入れてよいのです。
`enum-case-pattern`を含めて今まで出てきたすべてのパターンが対象です。

まず普通のパターンです。
```swift
enum E { case a, b, c }
let e = E.a

switch e {
  case .a: ()
  case .b: ()
  case .c: ()
}
```

つづいてAssociated Valueを持つenumのパターンです。
```swift
enum E {
  case value1(Int)
  case value2(Int, String)
}
let e = E.value1(10)

switch e {
  case .value1(0): print("value1 0")
  case .value1(..<0): print("value1 minus")
  case .value1(let i): print("value1 \(i)")

  case .value2(0, _): print("value2 0")
  case .value2(_, let string): print("value2 \(string)")
  case .value2(0...10, "str"): print("value2 0 to 10 and str");

  default: ()
}
```
enumの要素名の後ろの`()`は`taple-pattern`の`()`ですので結構なんでも入ります。

ではさらに
```swift
enum AnyBox {
  case value(Any)
}
let e = AnyBox.value(0)

switch e {
  case .value(is Int): print("value is Int")
  case .value(let str as String): print("value is String(\(str))")

  default: ()
}
```
`type-casting-pattern`ももちろん大丈夫です。

さらには
```swift
indirect Box {
  case .value(Int)
  case .box(Box)
}
let e = Box.box(.value(8))

switch e {
  case .box(.value(0...10)): print("0 to 10 in box")

  default: ()
}
```
`enum-case-pattern`の入れ子も大丈夫です。

`enum-case-pattern`は大抵の無茶は通ってしまいます。

# まとめ

やはり、Swiftの`case`と`enum`の組み合わせは極めて強力といえるでしょう。

`case`を上手に使いこなして一歩進んだプログラムを書いていきましょう。