【Swift】enum(列挙型)の使い方!値型enumと関連型enumとは

この記事からわかること
- Swiftのenum(列挙型)とは?
- 定義する方法と使い方
- 値型enumと関連値enumの特徴と違い
- Bool型などString/Int/Double以外の型を使用するには?
- RawRepresentableプロトコルとは?
- CaseIterableプロトコルで全要素を取得する方法
index
[open]
\ アプリをリリースしました /
Swiftのenum(列挙型)の使い方やメリットなどを自分の備忘録がてらまとめていきます。
enum(列挙型)とは?
Swiftの列挙型(enumerated type)は値を集合として名前をつけて管理することができます。enum
を使って定義し、型名は任意の名前を指定することができます。型名の最初の文字は大文字にすることが推奨されています。
中には複数の要素(メンバー)をcase
を使って列挙します。各メンバーは下記のように1行にまとめて宣言することも可能です。
列挙型をswitch文のcaseとして使う
列挙型は値によって処理を分岐させるswitch
文と組み合わせて使われることが多いです。
各要素に型や値を指定する:値型enum(raw value enum)
列挙型で定義したメンバーには型を指定することも可能です。指定できる型は「String型(文字列)」、「Int型(整数)」、「Double型(浮動小数点)」のみです。それ以外の型を指定した場合はエラーになってしまいます。
※1:RawRepresentableプロトコルについては後述しています。
また各要素に値を持たせることも可能です。
このように型や値を割り当てた列挙型を「値型enum(raw value enum)」と呼びます。
※rawValueとして渡せるのはリテラル(コンパイル時に値が既に定まっているもの)のみになっています。それ以外を渡そうとするとエラーが発生します。
列挙型のメンバーを参照する
列挙したメンバーにはenum
で宣言した型のドットシンタックスで参照できます。格納する変数に型が宣言してあればメンバー名だけでも参照可能になります。メンバー名がわからない場合はfromRaw(n)
でn番目のメンバーを取得可能です。存在しない番号が指定された場合はnil
が返ります。
出力してみると文字列「html」が出力されますが、変数の型を調べると「Language.Type
」となります。
列挙型の値を取得する
値型enumの要素に定義された値を取得するにはrawValue
を使います。
各要素の値が未定義の場合は整数型の場合は上から0.1.2...
の順番に、文字列型の場合は要素名と同名の文字列が自動的に格納されます。
値から該当する列挙型を取得する
値型enumの場合は指定した値から列挙型を取得することも可能です。その場合はイニシャライザLanguage(rawValue:)
を使用します。存在しない場合はnil
が返ります。
関連型enum: Associated Value
値型enumとは違いメンバーに関連値を紐付ける列挙型を関連型enum(Associated Value)と呼びます。値型の場合は列挙している集合自体に型を定義し、各メンバーには既に値が割り振られます。しかし関連型enumでは各メンバーごとに型を定義でき、また値を後からセットすることができます。
使い方とメリットを考えてみる
enumが活躍する時はグループの中に色々な値を定義したい時です。例えば「記事のカテゴリ」というグループの中に「HTML、CSS、PHP、Swift」を定義する場合を考えてみます。
特定の記事に対してカテゴリを付与する時、「1=HTML、2=CSS」のように数字と対応させるか、そのまま都度「HTML、CSS」と記述する方法になると思います。ですがそれぞれデメリットがあります。
数値の場合
可読性が低い
数値の場合はそれぞれに対応する表を別途用意(頭の中で)しておき、各値に紐づいた数値を指定することになります。
この場合自分しか識別できず、コメントとして残して置いたとしても可読性が低く、優しくありません。
文字の場合
誤入力が起こる
文字列の場合は都度、文字列を手打ちしないといけません。「HTML」などを「HMTL」などと誤入力する可能性がある上に、何でも入力出来てしまうのはリスクが大きいです。
列挙型の場合
この両方のデメリットを補ってくれるのが列挙型です。実際に列挙型で定義してみます。
先に列挙型Language
を定義しておき、Article
構造体のcategory
プロパティの型に指定します。これでcategory
プロパティに指定できるのはLanguage
に定義してある項目のみにすることができます。
列挙型を使用するメリット
メリット
- 可読性が高い
- コード補完で入力できる
- switch文で網羅しないとエラーが出る
可読性が高い
まずは可動性が向上します。選択できる項目は列挙型として明示的に定義してあるので参照もしやすくなります。
コード補完で入力

列挙型で定義した項目はLanguage.
(または型が決まっている状態で.
)まで入力すると予測が表示されるので手打ちしなくても簡単に指定することができるようになります。誤入力の可能性が極めて低くなるのは大きなメリットだと思います。
switch文でのエラー
expression failed to parse:
error: switch must be exhaustive

switch文を使った分岐処理を記述する際に列挙型を比較値として指定する場合、各項目を網羅できるように記述しないとエラーを起こしてくれます。これにより分岐処理の記述漏れを起こすことがなくなります。
RawRepresentableプロトコル
RawRepresentable
プロトコルはSwiftに元々定義されているプロトコルで、enumのcaseに値を持たせることができるプロトコルです。列挙型では元々「String型(文字列)」、「Int型(整数)」、「Double型(浮動小数点)」しか定義できませんがRawRepresentable
プロトコルを明示的に付与することでそれら以外の型の値を持たせることができるようになります。
また「String型(文字列)」、「Int型(整数)」、「Double型(浮動小数点)」はRawRepresentable
プロトコルがSwiftコンパイラが自動で付与してくれているのでrawValue
で値を取得できるようになっています。
列挙型の全要素を取得する:CaseIterable
CaseIterableプロトコルはSwift 4.2から使用可能になったプロトコルで定義されているプロパティの値をコレクション形式で取得できるallCases
プロパティが実装されます。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。