プログラムを作成するとき、曜日(月曜日、火曜日、水曜日、木曜日、金曜日、土曜日、日曜日)やカードのスート(スペード、クラブ、ダイヤ、ハード)のように決まった範囲の要素(種類)を持つ集合を扱う場合があると思います。
このようなときに便利なのが列挙型(Enumeration)です。
今回は、Swiftの列挙型について以下の観点で解説します。
- Swiftの列挙型の特徴
- Swiftの列挙型の値の指定方法
- Swiftの列挙型の使い方
参考本
[改訂新版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 WEB+DB PRESS plus
Swiftの列挙型の特徴
Swiftの列挙型は、関連する値のグループに共通の「型」を定義し、型安全(タイプセーフ)な方法でそれらの値を扱うことができるようにするものです。
列挙型は enum キーワードで始め、定義全体を波括弧内に配置します。
enum SomeEnumeration {
// 列挙型の定義
}
次の例は、コンパスの 4 点です。
case North
case South
case East
case West
}
列挙型で定義された(North、South、East、West のような)値は、列挙型のケースです。新しい列挙型のケースは、case キーワードで始めます。
列挙型の値にアクセスするためには以下のように型とケースを指定します。
この場合、Eastという値が出力されます。
次に、以下のように列挙型に定義されていない値を指定すると「CompassPoint型はそのような要素を持っていません」というエラーが出ます。
これは、決まった範囲の要素を持つ集合を「型」として定義することによって、その範囲内の値を安全に使うことができるように規定することができるということです。
例えば、列挙型ではなく文字列型などのように自由に要素を指定できる基本型にすると、予想外の要素の指定により実行時エラーになる可能性が高くなります。
さて、C や Objective-C と異なり、Swift での列挙型のケースは、生成時にデフォルトの整数値に割り当てられません。
上の CompassPoint の例で言えば、North、South、East、West が暗黙のうちに 0、1、2、3 になるわけではありません。
Swiftの場合、列挙型 CompassPoint の各ケースは、なにもしなければ、それ自体が値です。
また、Cと同じように各ケースに値(Raw値)を持たせることや、各ケースに関連する値(関連値)を持たせることができます。
このようにSwiftの列挙型は比較的柔軟な仕様になっています。
Swiftの列挙型の値の指定方法
それでは、Swiftの列挙型の値の指定方法について以下の観点で見ていきましょう。
- 関連値の指定
- Raw値の指定
関連値の指定
Swiftの列挙型 の各ケースは、なにもしなければ、それ自体が値です。
しかし、ケースの値の並びに別の型の関連値を持たせることが効果的な場合があります。
ケースの値に追加的な情報を持たせることができ、ケースを利用するたびにこの情報を変更することも可能です。
次の例を見てください。
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
これは、(Int, Int, Int, Int) 型の関連値を持つUPCA の値、または String 型の関連値を持つQRCodeの値のいずれかを取ることができる列挙型Barcodeを定義しています。
これにより、以下のようにして新たなバーコードを生成することができます。
この例は、新しい変数 productBarcode を生成し、関連するタプル値 (8, 85909, 51226, 3) を持つ Barcode.UPCAの値を代入しています。
また、次の例は、新しい変数 productBarcode を生成し、関連する文字列値 (ABCDEFGHIJKLMNOP) を持つ Barcode.QRCodeの値を代入しています。
Raw値の指定
Swiftの列挙型では列挙型のケースにすべて同じ型のデフォルト値(Raw 値)をあらかじめ持たせることができます。
なので、列挙型のケースの値とRaw値を結びつけて使いたい場合はRaw値を指定して使うこともできます。
例えば、以下のように定義すると、C言語と同じように、Planet型の各ケースに0から整数が割り当てられます。
case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
このRaw値にアクセスしたい場合、次のように記述します。
この場合「0」になります。
Raw値を指定したい場合、以下のようにします。
case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
この場合、最初のケースMercuryを1と指定しているので、次のケース以降、2、3と順番にRaw値が割り当てられます。
このRaw値ですが、整数だけでなく、文字列や文字、あるいは浮動小数点数の型にすることができます。
以下は、Raw値を文字型にした場合の例です。
case Tab = “\t”
case LineFeed = “\n”
case CarriageReturn = “\r”
}
また、次のようにRaw値を使って列挙型の値を初期化することができます。
// possiblePlanet は Planet? 型の Planet.Uranus
あらゆるRaw値に対応するとは限らないためraw 値のイニシャライザは常にオプショナルな列挙型のケースを返します。
この例では、possiblePlanet は Planet?(オプショナル Planet)型になります。
なお、オプショナルについては
Swiftのオプショナル
を参照してください。
Swiftの列挙型の使い方
列挙型の個々ケースの値は範囲が限定されているため、列挙型はswitch 文でよく使われます。
case North
case South
case East
case West
}
let directionToHead: CompassPoint = .South
switch directionToHead {
case .North:
print(“Lots of planets have a north”)
case .South:
print(“Watch out for penguins”)
case .East:
print(“Where the sun rises”)
case .West:
print(“Where the skies are blue”)
}
// “Watch out for penguins” と出力
この例の場合、以下のように理解することができます。
directionToHead の値について考える。
.North と一致するケースでは、”Lots of planets have a north” と出力する。
.South と一致するケースでは、”Watch out for penguins” と出力する、、など。
ここで、以下のようにcase .West:を省略すると「このswitch文は完全ではありません」というエラーが発生します。
case .North:
print(“Lots of planets have a north”)
case .South:
print(“Watch out for penguins”)
case .East:
print(“Where the sun rises”)
}
これも、決まった範囲の要素を持つ集合を「型」として定義することによって、その範囲内の値を安全に使うことができるように規定されているからです。
さて、以下のように、switch 文を使って列挙型の関連値を取得することができます。
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
var productBarcode = .QRCode(“ABCDEFGHIJKLMNOP”)
switch productBarcode {
case .UPCA(let numberSystem, let manufacturer, let product, let check):
print(“UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).”)
case .QRCode(let productCode):
print(“QR code: \(productCode).”)
}
// “QR code: ABCDEFGHIJKLMNOP.” と出力
この例の場合、switch のケース本体内で利用するために、let を置いて定数として各関連値を取り出しています。
以上、今回は、Swiftの列挙型について解説しました。