#はじめに
今回は**列挙型(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
で宣言するとstruct
やclass
と同じように型として扱えます。
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("コーラ")
}
enum
でswitch
がよく使われるのには理由があります。
上記の例で.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の列挙型は機能が多様で、他の言語と違い何かタイプ分けできるとなると頻繁にこの列挙型を使います。
覚えておくとコーディングが捗るはずなので使いながら慣れていってください。
今回の内容は以上です。
本記事とは別でプログラミング未経験からiOSアプリ開発が行えるようになることを目的とした記事を連載しています。
連載は以下にまとめていますのでそちらも是非もご覧ください。
http://naoyalog.com/