SwiftのEnumには便利な機能があって、enumを利用するときにenumの要素に付属する値を設定することができます。
代数的データ型(Algebraic data type)というそうです。
例えば、Httpエラーコードのenumを定義して、statusCodeやその時のresponseをmapで設定したい場合は以下のように書けます。
public enum HttpErrorType: Error {
case timedOutError
case cannotFindHost
case cannotConnectToHost
case statusCode(Int, [AnyHashable: Any]?)
}
判定するときは、以下のように書けます
switch errorType {
case .timedOutError:
print("タイムアウト")
case .cannotFindHost, .cannotConnectToHost:
print("サーバー接続できない")
case let .statusCode(401, detail):
print("ログインして")
case .statusCode(500, _):
print("サーバーエラー")
}
そして網羅チェックもしてくれます。
例えば、timedOutErrorをswitch文に入れてなければ、add missing case: '.timedOutError'
とコンパイラが知らせてくれます。
Kotlinのenumでは同じことができませんが、sealed
を使えば同じようなことができます。
Kotlinの sealed
はクラスの継承を制限するための修飾子です。
sealed
クラスはサブクラスを持つことができますが、それらのすべて同じファイルで宣言されなければなりません。 詳しくはコメント欄を確認してください。
( C#のsealed
はJavaのfinalと同等なのでC#の人は注意です。)
sealed class HttpErrorType
object TimedOutError : HttpErrorType()
object CannotFindHost : HttpErrorType()
object CannotConnectToHost : HttpErrorType()
data class StatusCode(val code: Int, val map: Map<String, Any>?) : HttpErrorType()
判定方法は、以下になります。
when (errorType) {
is TimedOutError -> print("タイムアウト")
is CannotFindHost, is CannotConnectToHost -> print("サーバー接続できない")
is StatusCode -> {
when (type.code) {
400 -> print("ログインして")
500 -> print("サーバーエラー")
else -> print("その他")
}
}
}.let { }
Kotlinでは、残念ながらパターンマッチができないのでStatusCodeの中身を分解して判断する必要があります。(その際にelseも必要になります)
最後の.let{}
は、コンパイラに網羅チェックをしてもらうために書いています。