【Swift】enum でIF文によるcase判定やassociated valueの取り出し方、enum同士を比較(==)する方法について【備忘録】
Swift でアプリ開発をしていると、enum は個人的に必須といえるほど頻繁に使用しています。
まだまだ駆け出しの身ですが、enum と associated value を覚えてからは多用しまくっています。
久しぶりにコードを書く時とかに「あれ?こういう時どうするんだっけ?」ということがないように、enum についての備忘録を残しておきます。
基本的な enum の定義
ここでは例として、API の通信結果を表す enum を定義してみます。
1 2 3 4 5 6 7 |
// enum APIResultType{ // 成功時の型(レスポンスデータ) case Success(data: String) // 失敗時の型(エラー時のステータスコードとエラーメッセージ) case Error(statusCode: Int, errorMessage: String) } |
API成功時には、その関連値(associated value)にレスポンスデータを持たせています。
失敗時は、ステータスコード(404など)と、エラーメッセージを関連値に持たせています。
enum の case を判別して関連値を取り出す
以下のような enum 変数があるとします。
1 |
let result = APIResultType.Success(data: "レスポンスデータです") |
この result から関連値(data)を取り出すためには、基本的にはswitch文を使用します。
1 2 3 4 5 6 7 |
// switch result { case let .Success(data: data): print(data) case let .Error(statusCode: statusCode, errorMessage: errorMessage): print(statusCode, errorMessage) } |
宗教上の理由でswitchを使いたくない
そんな人がいるかは分かりませんが...(笑)
でももう少し簡潔に書きたい時ってありますよね。
例えば、目的の case が .Success の時だけだったりすると、Switch 構文は書くのが面倒だったりするかもしれません。
そんな時は、if文を使用して任意のcaseの時だけ処理することができます。
1 2 3 4 |
// if case let .Success(data: data) = result{ print(data) } |
個人的には、caseを網羅する必要がない時はif文を使用することが多いです。
enum 同士をif文でイコール判定したい
enumが関連値を持たない場合は普通に==演算子を使用してイコール判定することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// enum SampleType{ case One case Two } let one = SampleType.One let two = SampleType.Two if one == two{ // 何らかの処理... }else{ // 何らかの処理... } |
しかし、enumが関連値を持つ場合(先ほどのAPIResultTypeのような場合)、上記のような書き方をするとエラーになってしまいます。
1 2 3 4 5 6 7 8 9 10 11 |
// let success = APIResultType.Success(data: "レスポンスデータです") let error = APIResultType.Error(statusCode: 404, errorMessage: "エラーです") if success == error{ print("同じ型です") } // -> エラーメッセージ // Binary operator '==' cannot be applied to two 'APIResultType' operands |
関連値を持つenum同士を==で比較したい場合は、enum を Equatableプロトコルに準拠させる必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// extension APIResultType: Equatable{ static func ==(lhs: APIResultType, rhs: APIResultType) -> Bool{ switch (lhs, rhs) { case (let .Success(lhsData), let .Success(rhsData)): return true case (let .Error(statusCode: lhsStatusCode, errorMessage: lhsErrorMessage), let .Error(statusCode: rhsStatusCode, errorMessage: rhsErrorMessage)): return true default: return false } } } |
これで、enum同士を比較することができるようになりました。
上の例は、関連値が同じかどうかまでは見ていません。厳密に関連値まで一致するかを比較する場合はコードを追加する必要がありますが、個人的にその用途はあまりないかなあと思っています。(分かりませんが・・)