列挙型を活用して返り値の?を外す

## 導入

以下のような問題を想定します。

```swift
func randomDirection() -> String{
    ["前","右","後","左"].randomElement()!
}
```

と定義された`randomDirection`を引数として、前であれば右、右であれば後といったように時計回りの方向を文字列で返す関数を作成せよ。

## 考察

🤔「switch使ったろ！」

```swift
func nextDirection(direction: String) -> String {
    switch direction {
    case "前":
        return "右"
    case "右":
        return "後"
    case "後":
        return "左"
    case "左":
        return "前"
    }
}
```

👮‍♂️「Switch must be exhaustive(網羅できてないよ)」

😅「」

😁「せや！case "左"をdefaultとして扱ったろ！」

```swift
func nextDirection() -> String {
    switch randomDirection() {
    case "前":
        return "右"
    case "右":
        return "後"
    case "後":
        return "左"
    default:
        return "前"
    }
}
```

🕵️‍♂️「値を取得する関数が`randomDirection()`のように簡単な関数であるとは限りません。それ以外の場合と一つの値を同じ処理にしてしまうのはバグの発見を遅らせてしまうため、いい実装とは言えません。」

😭「」

😁「せや！defaultの時はnilとしたろ！」

```swift
func nextDirection(direction: String) -> String {
    switch direction {
     case "前":
        return "右"
    case "右":
        return "後"
    case "後":
        return "左"
    default:
        return "前"
    default:
        return nil
    }
}
```

👮‍♂️「'nil' is incompatible with return type 'String'(返り値はStringなんだがw)」

😁「返り値`String?`にしたろ！」

🕵️‍♂️「問題は`String`で返す関数を作成することです。」

😭「『switchの分岐を全て網羅すること』と『型にオプショナルを加えないこと』とが両立できない」

## 列挙型(enum)を使う

🕵️‍♂️「列挙型を使うといいよ」

🧐「なるほど」

```swift
enum Direction {
    case 前
    case 右
    case 後
    case 左
}
```

🧐「とすれば`Direction`型は4つのどれかであるといえるのか。これらは変数の名前だから値を持たせる必要があるな。」

```swift
enum Direction: String {
    case 前 = "前"
    case 右 = "右"
    case 後 = "後"
    case 左 = "左"
}
```

🧐「`rawValue`を使えば値から型を作れるのか」

```swift
let direction = Direction(rawValue: direction)!
```

😁「これを使って関数を書き換えられる！」

```swift
func nextDirection(direction: String) -> String {
    let direction = Direction(rawValue: direction)!
    switch direction {
    case .前:
        return "右"
    case .右:
        return "後"
    case .後:
        return "左"
    case .左:
        return "前"
    }
}
```

👮‍♂️「」

## 省略する

🕵️‍♂️「caseとvalueが一致してたら省略できます。」

```swift
enum Direction: String {
    case 前
    case 右
    case 後
    case 左
}
```

😍「すごい」

## 工夫する

🕵️‍♂️「`CaseIterable`を使えば列挙型の全てを取得する`allCases`が使えます。」

```swift
enum Direction: String, CaseIterable {
    case 前
    case 右
    case 後
    case 左
}
```

🤔「配列いじればswitch自体使わなくても実装できそうだな。」

```swift
func nextDirection(direction: String) -> String {
    let allcases = Direction.allCases
    let direction = Direction(rawValue: direction)!
    let index = allcases.firstIndex(of: direction)!
    if index == allcases.count-1 {
        return allcases[0].rawValue
    }else {
        return allcases[index+1].rawValue
    }
}
```

😍「かっこいい」

🤔「けどもうここまできたら関数をいじるんじゃなくて列挙型の中身をいじった方が良くないか？」

```swift
enum Direction: String {
    case 前
    case 右
    case 後
    case 左
    var next: String {
        switch self {
        case .前:
            return "右" 
        case .右:
            return "後"
        case .後:
            return "左"
        case .左:
            return "前"
        }
    }
}
```

🤔「こんな感じになるな」

```swift
func nextDirection(direction: String) -> String {
    let direction = Direction(rawValue: direction)!
    return direction.next
}
```

😁「良い感じ！列挙型って便利！」



**終わり**