目的
Swift 言語の列挙型 では、各列挙子に Int 型 などの Raw 値を割り当てて、その値を使ってプログラムを制御できるようになっています。
独自のクラスでも条件を満たせば enum 型の Raw 値として利用できます。
独自クラスを Raw 値として使うための条件
* インスタンスをリテラルから変換できる
* Equatable プロトコルに準拠している
Raw 値として使えるクラスを定義する
とても簡単な例ですが、次のようにInt型 の値を保持するプロパティ value
を持ったクラス swift MyLiteral
を用意して、これを列挙型の Raw 値として使えるようにしました。
class MyLiteral : IntegerLiteralConvertible, Equatable {
var value:Int
required init(integerLiteral value: IntegerLiteralType) {
self.value = value
}
}
func ==(lhs: MyLiteral, rhs: MyLiteral) -> Bool {
return lhs.value == rhs.value
}
なんらかのリテラルから変換できるようにする
今回は 整数値リテラル から変換できるクラスにするために IntegerLiteralConvertible
プロトコルに準拠させています。
このプロトコルでは、イニシャライザ init(integerLiteral value: IntegerLiteralType)
の実装が求められています。
リテラルというのは、たとえば整数値であれば
100
といったテキストですし、小数点数であれば10.5
といったテキストです。文字列もリテラルで"TEXT"
といったテキストになります。
Equatableプロトコル に準拠させる
また Equatable
プロトコルに準拠させて、等号による一致判定ができるようにする必要があります。
このプロトコルで要求される実装は ==
演算子 なので クラス定義の外側で プロトコルが求める演算子を実装しています。
独自クラスを列挙型で使う
条件を満たしたクラスは、列挙型の Raw 値として利用できます。
enum MyEnum : MyLiteral {
case once = 1
case twice = 2
}
- 初期値はリテラルで設定します。
- 整数値リテラルで扱う場合は、省略時は最初の項目に 0 が割り当てられます。
独自クラスを使った列挙型を case 文で使う
列挙型のRaw として独自クラスを使っても、列挙型の扱い方は普段と何も変わりません。
let times = MyEnum.twice
switch times {
case .once:
println("ONCE")
case .twice:
println("TWICE")
}
列挙子から独自クラスのインスタンスを取得
独自クラスを使った列挙型の変数からは rawValue
プロパティを使ってインスタンスを取り出せます。
let raw:MyLiteral = times.rawValue
列挙子から直接、インスタンスを取り出すことも可能です。
let raw:MyLiteral = MyEnum.twice.rawValue
Raw 値から列挙子を取得
Raw 値で指定したクラスのインスタンスから、該当する列挙子を取得できます。
let value:MyEnum? = MyEnum(rawValue: raw)
このようにすると raw
変数に格納されている MyLiteral
型のインスタンスに該当する列挙子が取得できます。該当しない場合は nil
が得られます。
上記の rawValue:
には、インスタンス以外にリテラル値も直接指定できます。その場合は、リテラル値からインスタンスが作られた上で、該当する列挙子が探されるようです。
該当する列挙子を探すとき、その列挙型が想定するケースを順番にインスタンス化して、渡された Raw 値と
==
演算子で比較し、一致したものを「該当するもの」と判断するようです。
列挙子の扱われ方
- 列挙型の変数には リテラルの値 が格納されている様子
-
rawValue
にアクセスしたときに その都度 変換イニシャライザでインスタンスが 生成 される様子