複数の値をまとめて扱う列挙型enum
ここからは、複数データを管理するためのオブジェクトを見ていきましょう。
列挙型enumの宣言
同じ用途で使用する変数・オブジェクトをまとめてグループ化するのにもっとも適した型です。Swiftのenumは、JavaやC++などのほかの言語とは異なり、クラスのようにメソッドやプロパティを持つことができるのが大きな特徴です。クラスや構造体に比べ、簡単により見やすくデータを管理することができます。
1 2 3 |
enum 列挙型名 { case 列挙子 } |
列挙型名:複数の列挙子を管理・まとめて扱うための名前(グループ名)
列挙子:グループ化したいデータ(※数値は指定できません。定数/変数の命名規則と同じく、"100", "1apple"は列挙子にできず、"apple1" のような書き方であれば指定できます。試してみてください。)
例を見ていきましょう。
例えば、現在あなたのお店で栽培している商品は、apple, orange, bananaの3つしかありません。
この時、他の間違った商品を扱ったり(mangoという別の文字列が指定されたり)、間違ったデータが指定されたり(oranzeと入力されたり)するのを防ぐため、下記のようなenum(列挙型)を作成しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// enumの定義 Fruit型の宣言 enum Fruit { case apple case orange case banana } // 代入の仕方1 let myBasket = Fruit.apple // 代入の仕方2 let yourBasket: Fruit yourBasket = .orange |
データへのアクセスは、「列挙型名.列挙子」と記載します。(代入の仕方1)
また、列挙型名は「データ型」という扱いでもあります。(代入の仕方2)
型名が明示的である場合には、列挙型名を省略して「.列挙子」と記載することもできます。
それでは試しに代入時の列挙子を .mango や .oranze(綴り誤り)と指定してみてください。
誤った値を入れることはできませんね? Fruit型には定められた3つの値しか入りません。
このように、扱う値(定数/変数に入れる値や、関数使用時に引数へ渡す値)が決まっている場合に、enumで独自のデータ型を作成し、活用します。
Raw Values を指定して使う
まとめた値に、別のデータを付属させることができます。
宣言時に紹介したサンプルコードの列挙型名の隣に、:String を追加 & 下記11, 12行目のコードを追加してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
// enumの定義 Fruit型の宣言 enum Fruit: String { // : String を付け加える case apple case orange case banana } // 代入 let myBasket = Fruit.apple print(myBasket) //列挙子が出力される print(myBasket.rawValue) //列挙子に割り当てた値が出力される |
2つのprint文は、どちらも同じ出力結果となるでしょう。そこで今度は[: String]を[: Int]に変えてみてください。
すると、「列挙子に割り当てた値(.rawValue)」の出力結果が変化します。列挙子に整数値が割り当てられたことが確認できましたか?
・割り当てられる値
列挙子 | 整数のとき | 浮動小数点のとき | 文字列のとき |
apple | 0 | 0.0 | apple |
orange | 1 | 1.0 | orange |
banana | 2 | 2.0 | banana |
割り当てられる値は整数・浮動小数点・文字列の3つです。
任意の値を割り当てたいときはコード上で、
case apple = "りんご"
case orange = "オレンジ"
case banana = "バナナ" のように記載します。このとき、記載する型名はStringとします。
このように列挙子に別データを割り当てられることで、辞書のように(keyとvalue, 2列の表のように)扱うことができます。
逆に割り当てた値から、
let インスタンス名: 列挙型名 = 列挙型名(rawValue: 割り当てられた値)
という形で任意の要素(列挙子)を指定できます。例:let myBasket: Fruit? = Fruit(rawValue: 0)
このとき、「割り当てられた値」に存在しないものが指定された場合、nilが返りますのでオプショナル型の書き方で記載します。
※少々後の内容の話(エラー処理、プロトコルの内容になります)
今回、enum 列挙体名: 型名 とすることで、値を付与させることができました。
これはクラスの継承と同じように、[列挙体]に[型]の内容を反映させている、とイメージしてください。
これと同じ書き方で、enum 列挙体名: プロトコル名 とすることで、[列挙体]に[プロトコル]の内容を反映させることができます。つまり、後の内容で「値を付与させる以外でもこのような書き方をする」ということだけ頭の片隅に置いていただけると、混乱を避ける事ができます。
分岐構文と合わせて使う
また、enumは下記のように分岐と一緒に使うことも多いので、列挙子によって処理を分けるコードのサンプルを記載します。
・分岐文Ifでの扱い
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
enum Fruit { case apple case orange case banana } let herBasket = Fruit.banana //if文による比較 if herBasket == .apple { print("かごにはりんごがあります。") } else if herBasket == .orange { print("かごにはオレンジがあります。") } else if herBasket == .banana { print("かごにはバナナがあります。") } else { print("かごは空です。") } |
・分岐文switchでの扱い
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
enum Fruit { case apple case orange case banana } let hisBasket = Fruit.banana //switch文による比較 switch hisBasket { case .apple: print("かごにはりんごがあります。") case .orange: print("かごにはオレンジがあります。") case .banana: print("かごにはバナナがあります。") } |
※enumの値を全てcase文に指定すると、最後のdefaultの処理は不要となります。(defaultを記述すると警告メッセージが表示されます)。
割り当てデータなどと組み合わせて、複数データをまとめて扱いたい時に活用してみてください。
ここで紹介した書き方はほんの一部です。列挙型の中に列挙型を入れたりすることもできます。
enumを使いこなすには少し経験が必要ですが、利用するとより堅牢なプログラムを作成することができるようになります。