【プログラミング初心者】Swift基礎~列挙型~

#はじめに
今回は**列挙型(Enum)**について説明します。
Enumはプログラミングにおいて必須ではありませんが、Swiftに限るとよく使われる手法です。
他言語ではそれほど多くはない気もします。

#列挙型(Enum)とは？
`Enum`とはある関連した１つのグループに属する値それぞれに名前をつけたものです。
例えば飲み物を１つのグループとして考えます。
飲み物にはお茶、コーヒー、オレンジジュース、コーラなど様々な種類があります。
これらはそれぞれ飲み物グループに属する値です。

これを`Enum`を使わずプログラムで表現するには「１：お茶、２：コーヒー...」というように整数として対応付ける、「"tea"：お茶、"coffee"：コーヒー」と文字列として表現するかのどちらかになります。

このどちらにも問題があります。

まず整数で表現した場合、それぞれの数字がどの種類の飲み物に対応するのか一見しただけではわかりません。
そうなるとプログラムを管理する上で手間になりますし、誤った値を指定しても気づきにくくバグの原因になります。

```swift
var drink: Int = 1

if drink == 1 {
    print("お茶")
} else if drink == 2 {
    print("コーヒー")
} else if ...
```

文字列で表した場合、整数と違って人間の言葉なので把握しやすくなります。
ですが文字列は入力ミスが発生する可能性があり、"tea"をお茶と決めていても、例えば誤って"tee"という文字列が入力されていたとしてもSwiftの文法上は正しいためSwiftのエラーは発生しません。
これが原因で不具合が発生した場合、実装者が目を皿にして探す必要があります。
実際今下記の例をを書いてるときに間違っていました。。。

```swift:正しい例
var drink: String = "tea"

if drink == "tea" {
    print("お茶")
} else if drink == "coffee" {
    print("コーヒー")
} else if ...
```
```swift:誤った例
var drink: String = "tea"

if drink == "tee" {
    print("お茶")
} else if drink == "coffee" {
    print("コーヒー")
} else if ...
```

このようなミスを防いだり、純粋にプログラムを読みやすくする（可読性をあげるという）ために列挙型を使います。

#Enumの使い方
##定義方法
構文は以下となります。

```swift
enum 列挙型名 {
    case 値1
    case 値2
    case 値3
    ...
}
```
具体的に先程例にあげた飲み物を`Enum`として定義した例が以下となります。

```swift:Drink.swift
enum Drink {
    case tea
    case coffee
    case orangeJuice
    case cola
}
```
これは文字列と違いSwiftの型や値として定義しているため予測変換でも出ますし、誤っていればプログラムエラーを出してくれます。

##使い方
`enum`で宣言すると`struct`や`class`と同じように型として扱えます。

```swift
var drink: Drink
```
`enum`型に入る値は宣言時`case`として宣言した値のみです。
値は`.値１`または`enum名.値１`のように使用することができます。

```swift
var drink: Drink = .tea
または
var drink: Drink = Drink.tea  // この場合型アノテーションなしでOK
```
少し注意してほしいのは定義された値１、値２は**変数ではなく値**です。
つまり整数の「１」や文字列の「"文字"」などと同じ位置づけだと考えてください。

###if文での使い方
`if`で使う場合、`Int`などと同じように使えます。

```swift
var drink: Drink = .tea

if drink == .tea {
    print("お茶")
} else if drink == .coffee {
    print("コーヒー")
} else if ...
```
###switch文での使い方
`switch`でも使えます。
むしろ`enum`を使うときはほとんど`switch`文で処理を分岐させます。

```swift
var drink: Drink = .tea

switch drink {
case .tea:
    print("お茶")
case .coffee:
    print("コーヒー")
case .orangeJuice:
    print("オレンジジュース")
case .cola:
    print("コーラ")
}
```
`enum`で`switch`がよく使われるのには理由があります。
上記の例で`.cola`に対するケースを消してみます。

```swift
switch drink {
case .tea:
    print("お茶")
case .coffee:
    print("コーヒー")
case .orangeJuice:
    print("オレンジジュース")
}
```
すると`Switch must be exhaustive`というエラーが発生します。
条件を網羅できていないとSwiftが教えてくれるのです。
そのため「コーラの条件を書き忘れた！」というような漏れが発生しなくなります。
このSwiftの機能を使うため`switch`とよく併用します。

#値型Enum
##Enumに値を割り当てる
`enum`の値には整数か文字列のみですが、実際の値を割り当てることができます。
構文は以下になります。

```swift
enum 型名: 割り当てたい型名 {
    case 値１ = 割り当てたい値１
    case 値2 = 割り当てたい値2
    ...
}
```
`Drink`を例にして文字列を割り当てます。

```swift
enum Drink: String {
    case tea = "お茶"
    case coffee = "コーヒー"
    case orangeJuice = "オレンジジュース"
    case cola = "コーラ"
}
```
`Int`の場合は以下のようになります。

```swift
enum ErrorType: Int {
    case network = 1000
    case notFound = 404
    case server = 500
}
```
##値を参照する
割り当てた値は`enumの値.rawValue`で参照することができます。

```swift
let drink: Drink = .tea
print(drink.rawValue) // お茶

let error: ErrorType = .network
print(error.rawValue) // 1000
```
例えば引数で`enum`を受け取り、それを元に何か表示するというようなメソッドを作れたりします。

```swift
func printMessage(drink: Drink) {
    print("\(drink.rawValue)を飲みます")
}

var drink: Drink = .tea
printMessage(drink: drink)  // "お茶を飲みます"
```
##値からEnumを生成する
割り当てた値から`enum`の値を作成することもできます。
構文は以下となります。

```swift
型名(rawValue: 割り当てた値)
```

`Drink`を例にすると以下のようになります。

```swift
let drink = Drink(rawValue: "お茶") // drink == .tea
```
生成の際、`rawValue`には割り当てられていない値も指定できてしまいます。
その場合も考慮されて、この生成方法ではオプショナル型として値が返されます。
割り当てられていない値で初期化しようとした場合、nilが返ってきます。

```swift
let drink = Drink(rawValue: "水") // drink == nil
```
実際のアプリではサーバからの通信結果から`enum`を作りたいときなどによく使用します。

#メソッドを定義する
クラスや構造体と同様に`enum`でもメソッドを定義することができます。
構文は以下となります。

```swift
enum 型名 {
    case 値

    func メソッド名(引数名: 引数の型) -> 戻り値の型 {
        処理
    }
}
```
クラスなどのメソッド定義と同じですね。

呼び出し方は以下となります。

```swift
enumの値.メソッド名(引数名: 引数の値)
```
これもクラスと同様です。

`Drink`を例にします。
飲み物の色を返すメソッドを定義します。

```swift
enum Drink: String {
    case tea = "お茶"
    case coffee = "コーヒー"
    case orangeJuice = "オレンジジュース"
    case cola = "コーラ"
    
    func color() -> String {
        switch self {
        case .tea:
            return "茶"
        case .coffee:
            return "黒"
        case .orangeJuice:
            return "オレンジ"
        case .cola:
            return "黒"
        }
    }
}
```
メソッドの中で`self`を使用しています。
これもクラスなどと同じように自分自身を表し、自分がどんな値かによって処理が別れています。

```swift
let drink1: Drink = .tea
print(drink1.color()) // "茶"

let drink2: Drink = .coffee
print(drink2.color()) // "黒"
```
今はどういったときに使えるのか想像がつかないかもしれませんが、これは他の言語にはない便利な機能で実際アプリを作ることになったら多用します。
必要になったとき「Enumでもメソッドを定義できる」という程度には覚えておいた方がいいかと思います。

#最後に
今回は列挙型について紹介しました。
ここで紹介したものは基本的な部分で`enum`にはさらに多くの機能があります。

冒頭でも言いましたがSwiftの列挙型は機能が多様で、他の言語と違い何かタイプ分けできるとなると頻繁にこの列挙型を使います。
覚えておくとコーディングが捗るはずなので使いながら慣れていってください。

今回の内容は以上です。
本記事とは別でプログラミング未経験からiOSアプリ開発が行えるようになることを目的とした記事を連載しています。
連載は以下にまとめていますのでそちらも是非もご覧ください。
http://naoyalog.com/