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

はじめに

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

列挙型(Enum)とは?

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

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

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

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

var drink: Int = 1

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

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

var drink: String = "tea"

if drink == "tea" {
    print("お茶")
} else if drink == "coffee" {
    print("コーヒー")
} else if ...
var drink: String = "tea"

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

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

Enumの使い方

定義方法

構文は以下となります。

enum 列挙型名 {
    case 値1
    case 値2
    case 値3
    ...
}

具体的に先程例にあげた飲み物をEnumとして定義した例が以下となります。

enum Drink {
    case tea
    case coffee
    case orangeJuice
    case cola
}

これは文字列と違いSwiftの型や値として定義しているため予測変換でも出ますし、誤っていればプログラムエラーを出してくれます。

使い方

enumで宣言するとstructclassと同じように型として扱えます。

var drink: Drink

enum型に入る値は宣言時caseとして宣言した値のみです。
値は.値1またはenum名.値1のように使用することができます。

var drink: Drink = .tea
または
var drink: Drink = Drink.tea  // この場合型アノテーションなしでOK

少し注意してほしいのは定義された値1、値2は変数ではなく値です。
つまり整数の「1」や文字列の「”文字”」などと同じ位置づけだと考えてください。

if文での使い方

ifで使う場合、Intなどと同じように使えます。

var drink: Drink = .tea

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

switch文での使い方

switchでも使えます。
むしろenumを使うときはほとんどswitch文で処理を分岐させます。

var drink: Drink = .tea

switch drink {
case .tea:
    print("お茶")
case .coffee:
    print("コーヒー")
case .orangeJuice:
    print("オレンジジュース")
case .cola:
    print("コーラ")
}

enumswitchがよく使われるのには理由があります。
上記の例で.colaに対するケースを消してみます。

switch drink {
case .tea:
    print("お茶")
case .coffee:
    print("コーヒー")
case .orangeJuice:
    print("オレンジジュース")
}

するとSwitch must be exhaustiveというエラーが発生します。
条件を網羅できていないとSwiftが教えてくれるのです。
そのため「コーラの条件を書き忘れた!」というような漏れが発生しなくなります。
このSwiftの機能を使うためswitchとよく併用します。

値型Enum

Enumに値を割り当てる

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

enum 型名: 割り当てたい型名 {
    case 値1 = 割り当てたい値1
    case 値2 = 割り当てたい値2
    ...
}

Drinkを例にして文字列を割り当てます。

enum Drink: String {
    case tea = "お茶"
    case coffee = "コーヒー"
    case orangeJuice = "オレンジジュース"
    case cola = "コーラ"
}

Intの場合は以下のようになります。

enum ErrorType: Int {
    case network = 1000
    case notFound = 404
    case server = 500
}

値を参照する

割り当てた値はenumの値.rawValueで参照することができます。

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

let error: ErrorType = .network
print(error.rawValue) // 1000

例えば引数でenumを受け取り、それを元に何か表示するというようなメソッドを作れたりします。

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

var drink: Drink = .tea
printMessage(drink: drink)  // "お茶を飲みます"

値からEnumを生成する

割り当てた値からenumの値を作成することもできます。
構文は以下となります。

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

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

let drink = Drink(rawValue: "お茶") // drink == .tea

生成の際、rawValueには割り当てられていない値も指定できてしまいます。
その場合も考慮されて、この生成方法ではオプショナル型として値が返されます。
割り当てられていない値で初期化しようとした場合、nilが返ってきます。

let drink = Drink(rawValue: "水") // drink == nil

実際のアプリではサーバからの通信結果からenumを作りたいときなどによく使用します。

メソッドを定義する

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

enum 型名 {
    case 値

    func メソッド名(引数名: 引数の型) -> 戻り値の型 {
        処理
    }
}

クラスなどのメソッド定義と同じですね。

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

enumの値.メソッド名(引数名: 引数の値)

これもクラスと同様です。

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

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を使用しています。
これもクラスなどと同じように自分自身を表し、自分がどんな値かによって処理が別れています。

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

let drink2: Drink = .coffee
print(drink2.color()) // "黒"

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

最後に

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

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

今回の内容は以上です。

コメント

タイトルとURLをコピーしました