[Swift] caseの使い方を覚えて一段上のプログラミングを

# なにこれ？
あんまり知られてないcaseの使い方

# 基本

`case`といえば`switch`！
`switch`の簡単な例を見てみましょう。

```swift
func isA(_ c: Charactor) -> Bool {
  switch c {
    case "a", "A": true
    default: false
  }
}
```

普通ですね！
これは変数`c`に入れられた文字と文字`"a"`もしくは文字`"A"`が**同じ**であれば`true`になります。

## 準備
`case`といえば`enum`！
ということで以降で使用する`enum`を定義します。
```swift
indirect enum Box {
  case value(Int)
  case box(Box)
  case empty
}
```
`enum`の要素宣言の`case`は今回の話とは無関係です。

## if-case
`switch-case`に次いでよく使われるのが`if-case`です。
`switch-case`の`case`とは違い後ろに ` = 変数`が続きます。

```swift
func isEmpty(_ box: Box) -> Bool {
  if case .empty = box {
    return true
  }
  return false
}
```

## guard-case
あまり見たことがないですが`if-case`と同様に`gurad-case`も可能です。
```swift
func isValue(_ box: Box) -> Bool {
  guard case .value = box else {
    return false
  }
  return true
}
```

## for-case
ごくまれにみられますが、`for-case`も可能です。
`switch-case`同様後ろには何も続きません。
`Sequence`の要素のうち条件に合致するときのみコードブロックが実行されます。
```swift
func printValues(_ boxes: [Box])  {
  for case .value(let i) in boxes {
    print(i)
  }
}
```
`case`では`.value`の値にある部分に`let i`と記述することで、Associated Valueを変数`i`に代入することができます。
これは`case`が使える場面では常に有効です。

## while-case
僕も初めて見ました。`while-case`もいけます。

```swift
func deepSearch(_ box: Box) -> Int? {
  var box = box
  
  while case .box(let inner) = box {
    box = inner
  }
  
  guard case .value(let value) = box else {
    return nil
  }
  return value
}


let box = Box.box(Box.box(Box.value(1)))

print(deepSearch(box))
/// prints Optional(1)
```

## repeat-case ?
出来ません。
Swiftの制御フローで唯一`repeat`だけは条件に`case`が使えません。
残念。

また`case`は式ではないため式が使える場所どこでも使えるわけではありません。
例えばなんか使えそうな気がする三項演算子でも使用不能です。

# Equatableとcase

当たり前ではありますが`Equatable`な型はすべて`case`で使えます。
```swift
let v: Int = 0
switch v {
  case 0: print("0")
  case 1: print("1")
  default: print("other")
}
```

# 範囲指定などはどうなっているのか
範囲を指定している`case`はどのようになっているのか
```swift
let v: Int = 0
switch v {
  case ..<0: print("Minus")
  case 0: print("0")
  default: print("Plus")
}
```
これは`~=`という関数（オペレータ）を実装することで実現できます。
上の場合は
```swift
extension RangeExpression {
  public static func ~= (pattern: Self, value: Bound) -> Bool {
    pattern.contains(value)
  }
}
```
が実装されているため機能します。

第一引数（左辺）がパターン、第二引数（右辺）が指定される値になります。
この関数（オペレータ）は**パターンマッチ演算子**と呼ばれています。

実は`case`はすべてパターンマッチ演算子`~=`で検査が行われています。
先に書いた`Equatable`も`==`を使っているのではなく、
```swift
public func ~= <T: Equatable>(a: T, b: T) -> Bool {
  return a == b
}
```
が標準ライブラリに入っていることで`case`に使えるようになっています。

# カスタムタイプとパターンマッチ
ここまでに書いた通り、`~=`を書けばいろいろなパターンマッチが可能となります。
例えば正規表現でパターンマッチなども可能になります。

```swift
struct RE {
  private var re: Regex<AnyRegexOutput>
  
  init(_ reg: String) {
    do {
      re = try Regex<AnyRegexOutput>(reg)
    }
    catch {
      re = try! Regex<AnyRegexOutput>("")
    }
  }
  
  static func ~= (_ lhs: Self, _ rhs: String) -> Bool {
    (try? lhs.re.firstMatch(in: rhs)) != nil
  }
}
```
を導入すれば、
```swift
func hoge(_ string: String) -> String {
  switch string {
    case RE("a"): "a"
    case RE("ho*ge"): "ho*ge"
    default: "other"
  }
}

print(hoge("abc"))
/// prints a

print(hoge("hooooooooooooooooooge"))
/// prints ho*ge

print(hoge("piyo"))
/// prints other
```
のように`switch-case`で正規表現が利用できるようになります。
*（ここで提示した`RE`は最低限動くようにしただけのものです。実際に利用するのはやめましょう。）*


# enumのAssociated Valueとパターンマッチ
`Box.value`が特定の範囲の値の時などに何かしたいというときに使うのがこちらです。

```swift
func isValuePlus(_ box: Box) -> Bool {
  switch box {
    case .value(1...): true
    default: false
  }
}
```
見た目としてはかなり不思議です。
これは少しややこしくて、`box`が`.value`であればカッコ内の値とAssociated Valueをパターンマッチ演算子で検査する、という動作になります。

これは以下と同じです。
```swift
func isValuePlus(_ box: Box) -> Bool {
  switch box {
    case .value(let value) where 1... ~= value: true
    default: false
  }
}

// あるいは
func isValuePlus(_ box: Box) -> Bool {
  if case .value(let value), case 1... = value {
    return true
  }
  return false
}
```

# オプショナルとパターンマッチ
オプショナルを検査する`case`では糖衣構文を利用することができます。
```swift
func isZero(_ i: Int?) -> Bool {
  if case .some(0) = i {
    return true
  }
  return false
}
```
これを糖衣構文を利用して書き換えるとこうなります。
```swift
func isZero(_ i: Int?) -> Bool {
  if case 0? = i {
    return true
  }
  return false
}
```

次に、ある`Optional<Int>`な値を３つの場合、`nil`, `nil`でなく`0`未満, `nil`でなく`0`に分けることを考えます。
これも先ほどの「enumのAssociated Valueとパターンマッチ」と同じです。

```swift
func sign(_ value: Int?) -> String {
  switch value {
    case .some(..<0): "Minus"
    case .some(0...): "0 or Plus"
    default: "Nil"
  }
}
```
これは以下のように書くこともできます。

```swift
func sign(_ value: Int?) -> String {
  switch value {
    case (..<0)?: "Minus"
    case (0...)?: "0 or Plus"
    default: "Nil"
  }
}
```


# タプルとcase

タプルを`switch-case`で場合分けすることがありますが、こちらにも少し変わった方法があるので見てみましょう。

みんな大好き`FizzBuzz`です。
```swift
func fizzBuzz1(_ i: Int) -> String {
  guard i > 0 else { fatalError() }

  switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) {
    case (true, true): return "FizzBuzz"
    case (true, _): return "Fizz"
    case (_, true): return "Buzz"
    default: return "\(i)"
  }
}
```
こちらの２番目３番目の`case`に含まれる`_`はマッチしてもしなくてもよい、つまりどんな値でも`true`になるパターンです。

# まとめ
Swiftの`case`はとても強力です。
うまく使うことで複雑なコードが簡素になることもあります。
条件分岐を考えるときは`case`のことを少しだけ思い出してあげてください。