enum
Swift

Swiftのenumについてまとめてみる

"enumってswitch文みたい"
なんて思っていた初心者がenumが使いたくなることを目指して調べてみました。

enumとは

Swiftの列挙型。
とりあえず、関連した値のグループを定義したもの。
チョコ、クッキー、飴、ケーキをお菓子として定義するみたいなものだと考えておけば大丈夫。
この時点で冒頭のswitch文のくだりについて答えが出てるんですがそれは追い追い…

何に使うのか

それで、じゃあ一体何にそれを使うのかということになるんですが、

定数を列挙します。
データ構造を定義するのに使います。

…うーん、物足りないですね。
ということで先輩エンジニアさんたちがまとめているのをさらっと覗くことに。
その中でも、enumを使うメリットとして高確率で上がってきているのが

”読みやすい”

ちょっと使いたくなってきました笑
それではもう一押し!
想像してみてください。今、何かの関係で今コードを読んでいるとします。
上からいろんな値が定義されています。
なになに?人参、ポテチ、ひき肉、ブロッコリー、ビスケット…
「は⁉︎」ってなりますよね。
こんなのがまだまだあります。
この値がどう使われるかもどんな値の集団なのかもわかりません。
頑張って下まで読むと動作とか出てきてなんとなくわかるかもしれませんが。
ここでenumを使うと…

なんということでしょう!
あんなにバラバラだった値がスッキリと定義されています。
読むのが大変だった定数の山は綺麗に並べ替えられ、かつ先頭には集団の特性がわかる名前が。
メンテナンスのたびに大変だった作業も、いまでは思い出に。

まあこんなビフォー○フターみたいにまではいかないとしても
可読性はグッとあがります。
場合よっては型定義の必要も最低限で済むのでキーボードを叩く時間も削減できます。
それでは、実際の使い方について書いていきます。

基本形

書き方

enum Sweets {
    case chocolate
    case cookie
    case candy
    case cake
}

きっと皆さんもご存知の形です。
特にめぼしいこともないですが。。。
あとは、このようにcaseを省略することもできます。

enum Sweets {
    case chocolate, cookie, candy, cake
}

呼び出し方

呼び出し方ですが通常は変数や定数に入れてから使用するようです。
そして一度定義した場合はenum名の省略が可能です。

enum Sweets {
    case chocolate
    case cookie
    case candy
    case cake
}
var eatsweets: Sweets
eatsweets = Sweets.candy
eatsweets = .candy    //型がわかっているので省略可能

値型enum

enum Sweets: String {
        case chocolate = "チョコレート"
        case cookie = "クッキー"
        case candy = "飴"
        case cake = "ケーキ"
}
enum Numbers: Int {
        case first = 1
        case second = 2
        case third = 3
}

let eatsweets: Sweets = .cookie
eatsweets.rawValue //クッキー

let numbers: Numbers = .first
numbers.rawValue //1

それぞれに指定した型の値をつけることができます。
enum enum名: 型名
という風です。
呼び出すときはrawValueを使います。

また、型だけ指定して値を入れないことも可能です。

enum Sweets: String {
        case chocolate
        case cookie
        case candy
        case cake
}
enum Numbers: Int {
        case first
        case second
        case third
}

let eatsweets: Sweets = .cookie
eatsweets.rawValue //cookie

let numbers: Numbers = .first
numbers.rawValue //0

このように値を指定しなかった場合、
String型のときはcaseで設定した値がそのまま反映されます。
Int型のときは値が0から始まります。

関連型enum

caseに複数の値を持たせることも可能です。
型さえ指定しておけば名前をつけなくても大丈夫です。
呼び出し方はどちらも同じようになります。

enum Meal {
        case breakfast(name: String, calorie: Int)
        case lunch(name: String, calorie: Int)
//型だけ指定
        case dinner(String, Int)
}

var meal = Meal.breakfast(name: "パン", calorie: 300)
meal = Meal.lunch(name: "ラーメン", calorie: 500)
//型だけ指定
meal = Meal.dinner("サラダ", 150)

switch meal {

case .breakfast(let name, let calorie) where calorie <= 500:
     print("\(name)は高カロリーです!")
case .breakfast(let name):
     print("\(name)は低カロリーです")

case .lunch(let name, let calorie) where calorie <= 500:
     print("\(name)は高カロリーです!")
case .lunch(let name):
     print("\(name)は低カロリーです")

case .dinner(let name, let calorie) where calorie <= 500:
     print("\(name)は高カロリーです!")
case .dinner(let name):
     print("\(name)は低カロリーです")

default:
   return

}
//  サラダは低カロリーです

メソッドを定義する

enumにメソッドを定義することができます。

enum Signal {
    case blue
    case yellow
    case red

    func meaning: String {
        switch self {
        case .blue:
            return "進め"
        case .yellow:
            return "注意"
        case .red:
            return "止まれ"
        }
    }
}

let signal = Signal.Yellow
print(signal.meaning())

.メソッド名でメソッド処理の返り値を得られます。
このメリットはcaseの値分の処理がないとエラーが出ることです。
caseの量が増えた時に処理を書くのを忘れた!なんてことを防ぐことができます。

ネスト

調べている最中にこれはすごい!と感動したのがこれ。

例えばRPGにはキャラクター、武器、防具があります
武器や防具はキャラクターが装備するものなので、キャラクターを通してしかアクセスさせたくない時など、その関係性を階層構造で表すことができ、アクセスの方法も直感的なコードになります。

一気に設定するのが楽になりますね!
テンションが上がるままに書いたコードがこちら。

struct Character {
     enum CharacterName {
        case girl
        case boy
        case teacher
     }
     enum Weapon {
        case eraser
        case pencil
        case attendancerecord
        case socks
     }
     let type: CharacterName
     let weapon: Weapon
}

let state = Character(type: .girl, weapon: .pencil)
print("\(state.type)\(state.weapon)を持っています")
//girlはpencilを持っています

キャラクターから武器までぱっと概要を把握できます。
他にもネストの仕方はいろいろあるみたいです。
…が、力尽きたので割愛させてもらいます。

まとめ

そんなこんなでざっくりとまとめてみて分かったのは、
enumすごい便利なんですけど!

caseの部分だけ見てswitch文と似てるなーなんて思ってごめんなさい。
人(?)は見た目だけで判断するものじゃありませんね…
上手に使えるまではまだまだかかりそうですが積極的に使っていきたいと思いました。

参考にさせてもらったサイト