楽水

人々の創造が自由に表現できる舞台づくり

Swift

Swiftの列挙型をわかりやすく解説

投稿日:2020年8月29日 更新日:


プログラムを作成するとき、曜日(月曜日、火曜日、水曜日、木曜日、金曜日、土曜日、日曜日)やカードのスート(スペード、クラブ、ダイヤ、ハード)のように決まった範囲の要素(種類)を持つ集合を扱う場合があると思います。
このようなときに便利なのが列挙型(Enumeration)です。
今回は、Swiftの列挙型について以下の観点で解説します。

  • Swiftの列挙型の特徴
  • Swiftの列挙型の値の指定方法
  • Swiftの列挙型の使い方

参考本
[改訂新版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 WEB+DB PRESS plus

Swiftの列挙型の特徴

Swiftの列挙型は、関連する値のグループに共通の「型」を定義し、型安全(タイプセーフ)な方法でそれらの値を扱うことができるようにするものです。
列挙型は enum キーワードで始め、定義全体を波括弧内に配置します。
enum SomeEnumeration {
// 列挙型の定義
}
次の例は、コンパスの 4 点です。

enum CompassPoint {
case North
case South
case East
case West
}

列挙型で定義された(North、South、East、West のような)値は、列挙型のケースです。新しい列挙型のケースは、case キーワードで始めます。
列挙型の値にアクセスするためには以下のように型とケースを指定します。

print(CompassPoint.East)

この場合、Eastという値が出力されます。
次に、以下のように列挙型に定義されていない値を指定すると「CompassPoint型はそのような要素を持っていません」というエラーが出ます。

CompassPoint.Monday

これは、決まった範囲の要素を持つ集合を「型」として定義することによって、その範囲内の値を安全に使うことができるように規定することができるということです。
例えば、列挙型ではなく文字列型などのように自由に要素を指定できる基本型にすると、予想外の要素の指定により実行時エラーになる可能性が高くなります。

さて、C や Objective-C と異なり、Swift での列挙型のケースは、生成時にデフォルトの整数値に割り当てられません。
上の CompassPoint の例で言えば、North、South、East、West が暗黙のうちに 0、1、2、3 になるわけではありません。
Swiftの場合、列挙型 CompassPoint の各ケースは、なにもしなければ、それ自体が値です。
また、Cと同じように各ケースに値(Raw値)を持たせることや、各ケースに関連する値(関連値)を持たせることができます。
このようにSwiftの列挙型は比較的柔軟な仕様になっています。

Swiftの列挙型の値の指定方法

それでは、Swiftの列挙型の値の指定方法について以下の観点で見ていきましょう。

  • 関連値の指定
  • Raw値の指定

関連値の指定

Swiftの列挙型 の各ケースは、なにもしなければ、それ自体が値です。
しかし、ケースの値の並びに別の型の関連値を持たせることが効果的な場合があります。
ケースの値に追加的な情報を持たせることができ、ケースを利用するたびにこの情報を変更することも可能です。
次の例を見てください。

enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}

これは、(Int, Int, Int, Int) 型の関連値を持つUPCA の値、または String 型の関連値を持つQRCodeの値のいずれかを取ることができる列挙型Barcodeを定義しています。
これにより、以下のようにして新たなバーコードを生成することができます。

var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)

この例は、新しい変数 productBarcode を生成し、関連するタプル値 (8, 85909, 51226, 3) を持つ Barcode.UPCAの値を代入しています。
また、次の例は、新しい変数 productBarcode を生成し、関連する文字列値 (ABCDEFGHIJKLMNOP) を持つ Barcode.QRCodeの値を代入しています。

productBarcode = .QRCode(“ABCDEFGHIJKLMNOP”)

Raw値の指定

Swiftの列挙型では列挙型のケースにすべて同じ型のデフォルト値(Raw 値)をあらかじめ持たせることができます。
なので、列挙型のケースの値とRaw値を結びつけて使いたい場合はRaw値を指定して使うこともできます。
例えば、以下のように定義すると、C言語と同じように、Planet型の各ケースに0から整数が割り当てられます。

enum Planet: Int {
case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}

このRaw値にアクセスしたい場合、次のように記述します。

Planet.Mercury.rawValue

この場合「0」になります。
Raw値を指定したい場合、以下のようにします。

enum Planet: Int {
case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}

この場合、最初のケースMercuryを1と指定しているので、次のケース以降、2、3と順番にRaw値が割り当てられます。
このRaw値ですが、整数だけでなく、文字列や文字、あるいは浮動小数点数の型にすることができます。
以下は、Raw値を文字型にした場合の例です。

enum ASCIIControlCharacter: Character {
case Tab = “\t”
case LineFeed = “\n”
case CarriageReturn = “\r”
}

また、次のようにRaw値を使って列挙型の値を初期化することができます。

let possiblePlanet = Planet(rawValue: 7)
// possiblePlanet は Planet? 型の Planet.Uranus

あらゆるRaw値に対応するとは限らないためraw 値のイニシャライザは常にオプショナルな列挙型のケースを返します。
この例では、possiblePlanet は Planet?(オプショナル Planet)型になります。
なお、オプショナルについては
Swiftのオプショナル
を参照してください。

Swiftの列挙型の使い方

列挙型の個々ケースの値は範囲が限定されているため、列挙型はswitch 文でよく使われます。

enum CompassPoint {
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文は完全ではありません」というエラーが発生します。

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”)
}

これも、決まった範囲の要素を持つ集合を「型」として定義することによって、その範囲内の値を安全に使うことができるように規定されているからです。
さて、以下のように、switch 文を使って列挙型の関連値を取得することができます。

enum Barcode {
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の列挙型について解説しました。

-Swift
-,

執筆者:

関連記事

Swiftのクロージャについてわかりやすく解説

Swiftのクロージャって何? いまひとつわからない、という方むけに、今回は、Swiftのクロージャについて以下の観点で丁寧に解説します。 Swiftのクロージャとは何か Swiftのクロージャ式 S …

Swiftの関数【Swiftの関数の書き方をわかりやすく解説】

Swiftの関数は、特定のタスクを実行する独立したコードブロックです。 Swiftの関数は、パラメータ名の無いシンプルな C スタイルの関数から、パラメータごとにローカルと外部のパラメータ名がある複雑 …

Swiftのメモリ管理【weakやunownedをわかりやすく解説】

Swiftのプログラムでweakやonwnedというキーワードをみたことはありませんか? これはSwiftが採用しているARCというメモリ管理の仕組みに関係しています。 今回は以下の観点でSwiftの …

Swiftのプロパティラッパーをわかりやすく解説

Swiftのプロパティには、プロパティラッパーという機能が用意されています。 今回は、Swiftのプロパティラッパーについて以下の観点で解説します。 プロパティラッパーとは何か プロパティラッパーの使 …

Swiftクロージャによる強い参照の循環参照とその解決

Swiftのメモリ管理 では、 2 つのクラスインスタンスのプロパティが互いに強い参照を持つことで、どのようにして強い参照の循環参照が生成されるのかを見てきました。 また、強い参照の循環参照を切るため …