Swift 5.3 日本語化計画 : Swift 5.3


列挙型


可能な値のリストを定義するカスタム型をモデルとします。


列挙型 は、関連する値のグループ用の一般的な型を定義し、コード内で型が安全な方法でそれらの値を処理できるようにします。


あなたが C に精通している場合、C の列挙型は整数値のセットに、関連した名前を割り当てることを知っているでしょう。Swift での列挙型は、より柔軟であり、列挙型の各 case に値を提供する必要はありません。もし値 (生の 値として知られています) が各列挙型 case に対して提供されている場合、値は、文字列、文字、または任意の整数値や浮動小数点型です。


また、列挙型の case は、union やバリアントが他の言語でするように、それぞれ異なる case 値と一緒に保存される 全て の型の関連する値を指定できます。それに関連する適切な型の値の異なるセットを持っているそれぞれが一つの列挙型の一部として、関連する case の共通するセットを定義できます。


Swift での列挙型は、それ自身の権利としてファーストクラスの型です。それらは、列挙型の現在の値に関する追加情報や、列挙型が表す値に関連する機能を提供するために、インスタンス・メソッドを提供するために、計算されたプロパティなどを、伝統的にクラスによってのみサポートされている多くの機能を採用しています。列挙型はまた、case の初期値を提供するために、イニシャライザも定義できます。元の実装を超えてそれらの機能を拡張することができ、標準的な機能を提供するためのプロトコルに準拠できます。


これらの機能の詳細については、プロパティメソッド初期化拡張機能、および プロトコル を参照してください。


列挙型の構文


enum キーワードで列挙型を導入し、中括弧のペアの中にその全体の定義を配置して下さい。


  1. enum SomeEnumeration {
  2. // enumeration definition goes here
  3. }


ここでは、コンパスの主な4つのポイントの例を示します。


  1. enum CompassPoint {
  2. case north
  3. case south
  4. case east
  5. case west
  6. }


列挙型で定義された値 (北、南、東、西 (north, south, east, west) のような) は、その 列挙型の case です。case キーワードは、新しい列挙型の case を導入するのに使用します。


注意: C や Objective-C のような言語とは異なり、Swift の列挙型の case は、デフォルトでは整数値は持っていません。上記の CompassPoint の例では、north,south,eastwest0、1、23 とは暗黙的には等しくありません。その代わり、異なる列挙型の case はそれ自体の権利で、CompassPoint の明示的に定義された型で、れっきとした値があります。


複数の case は、コンマで区切って1行に表示できます。


  1. enum Planet {
  2. case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
  3. }


各列挙型の定義は、真新しい型を定義します。Swift の他の型と同様に、それらの名前は(CompassPointPlanet などのように)大文字で始まります。それらは自明に読み取られるように、複数名よりもむしろ単数名の列挙型を与えて下さい:


var directionToHead = CompassPoint.west



CompassPoint の取りうる値の1つで初期化されると、directionToHead の型が推測されます。ひとたび directionToHeadCompassPoint として宣言されると、短いドット構文を使用して、異なる CompassPoint 値にそれを設定できます。


directionToHead = .east



directionToHead の型は、すでに知られており、その値を設定するときには、型を抜かすことができます。これは、明示的に型指定された列挙型の値で作業するとき、非常に読みやすいコードになります。



switch 文で列挙型の値と一致


switch 文を使って個々の列挙型の値に一致する事ができます。


  1. directionToHead = .south
  2. switch directionToHead {
  3. case .north:
  4. print("Lots of planets have a north")
  5. case .south:
  6. print("Watch out for penguins")
  7. case .east:
  8. print("Where the sun rises")
  9. case .west:
  10. print("Where the skies are blue")
  11. }
  12. // prints "Watch out for penguins"


このコードは以下のように読むことができます:


"directionToHead の値を考えましょう。それが .north に等しい場合、"惑星の多くには北がある" と印刷します。.south に等しい場合、"ペンギンに気をつけろ" と印刷します。"


...等々。


フロー制御 で説明したように、列挙型の case を考慮した場合、switch 文は、網羅的でなければなりません。.west が省略された case (場合)では、それが CompassPoint case の完全なリストを考慮していないので、このコードは、コンパイルされません。網羅性を要求する場合、列挙型 case が誤って省略されていないことを保証します。


すべての列挙型の case を提供することが適切でない場合には、明示的に対処されていないすべての case をカバーするために、default の case を提供できます。


  1. let somePlanet = Planet.earth
  2. switch somePlanet {
  3. case .earth:
  4. print("Mostly harmless")
  5. default:
  6. print("Not a safe place for humans")
  7. }
  8. // prints "Mostly harmless"


列挙型 case の繰り返し処理


いくつかの列挙型では、その列挙型のすべての case のコレクションを持つと便利です。これを有効にするには、列挙型の名前の後に : CaseIterable を記述します。Swift は、すべての case のコレクションを列挙型の allCases プロパティとして公開します。以下に例を挙げます:


  1. enum Beverage: CaseIterable {
  2. case coffee, tea, juice
  3. }
  4. let numberOfChoices = Beverage.allCases.count
  5. print("\(numberOfChoices) beverages available")
  6. // Prints "3 beverages available"


上記の例では、Beverage.allCases と書いて、Beverage 列挙型のすべての case を含むコレクションにアクセスします。他の全てのコレクションと同様に allCases を使用できます。コレクションの要素は列挙型のインスタンスなので、この場合は Beverage 値です。上記の例では、いくつの case があるかを数え、下の例では、for ループを使用してすべての case を反復処理しています。


  1. for beverage in Beverage.allCases {
  2. print(beverage)
  3. }
  4. // coffee
  5. // tea
  6. // juice


上記の例で使用されている構文は、列挙型を CaseIterable プロトコルに準拠するものとしてマークします。プロトコルの詳細については、プロトコル を参照してください。



関連する値


前の節の例では、列挙型の case が、どのようにそれ自体の権利で値を定義されている (型付けされている) かを示しました。Planet.earth に定数または変数を設定し、後でこの値を確認できます。しかし、これらの case の値と一緒に他の型の値を格納できることが便利な場合があります。この追加情報は 関連する値 と呼ばれ、それはその case をコードで値として使用するたびに変化します。


全ての与えられた型の関連する値を格納するために Swift の列挙型を定義することができ、必要に応じて値の型は、列挙型の各 case ごとに異なる事ができます。これらのような列挙型は、他のプログラミング言語では 差別組合、標識のついた組合、または バリアント として知られています。


たとえば、在庫追跡システムが、バーコードの二つの異なる型で製品を追跡する必要があると仮定しましょう。一部の製品は、0 から 9 までの数字を使用した UPC 形式の 1D バーコードでラベルされています。それぞれのバーコードには "ナンバーシステム" の数字があり、5つの"メーカーコード" の数字が続き、5つの"製品コード" の数字が続きます。これらには、コードが正しくスキャンされたことを確認するために"チェック" の数字が続きます。



barcode_UPC_2x


他の製品は、ISO 8859-1 の文字をどれでも使用することができ、2953 文字までの長さの文字列をコード化できる、QR コード形式の 2D バーコードでラベルされています。


barcode_QR_2x


在庫追跡システムでは、4つの整数のタプルとして UPC バーコードを格納することができ、そして QR コードのバーコードは任意の長さの文字列を格納できるのが便利です。


Swift では、どちらかの型の製品のバーコードを定義する列挙型は以下のようになります。


  1. enum Barcode {
  2. case upc(Int, Int, Int, Int)
  3. case qrCode(String)
  4. }


これは次のように読めます:


"(Int,Int,Int,Int)型の関連する値で upc の値を取るか、または String 型の関連する値で qrCode の値のいずれかの値を取れる Barcode と言う列挙型を定義します。"


この定義は、実際の Int または String の値を全く提供していませんーそれは Barcode.upc または Barcode.qrCode に等しいときに Barcode 定数と変数が格納できる、関連する値の だけを定義しています。


新しいバーコードは、いずれかの型を使用してその後作成できます。


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



この例は、productBarcode という新しい変数を作成し、関連した (8、85909、51226、3) のタプル値で Barcode.upc の値をそれに代入します。


同製品には、バーコードの異なる型を割り当てられます。


productBarcode = .qrCode("ABCDEFGHIJKLMNOP")



この時点で、元の Barcode.upc とその整数値は、新しい Barcode.qrCode とその文字列値によって置き換えられます。Barcode 型の定数と変数は .upc.qrCode (共に関連付けられた値を持つ) のいずれかを格納できますが、それらは与えられた時点ではそれらのいずれか一つしか格納できません。


Switch 文で列挙型の値と一致 での例と同様に、switch 文を使用してさまざまなバーコード型を確認できます。この時には、しかし、関連する値は、switch 文の一部として抽出できます。switch case の本体内で使用するため (let に引き続いて) 定数または (var に引き続いて) 変数として、各々関連する値を抽出します。


  1. switch productBarcode {
  2. case .upc(let numberSystem, let manufacturer, let product, let check):
  3. print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
  4. case .qrCode(let productCode):
  5. print("QR code: \(productCode).")
  6. }
  7. // prints "QR code: ABCDEFGHIJKLMNOP."


列挙型の case に関連した値をすべて定数として抽出した場合、またはすべてを変数として抽出した場合は、簡潔にするために、case 名の前に単一の var または let 注釈を書けます:


  1. switch productBarcode {
  2. case let .upc(numberSystem, manufacturer, product, check):
  3. print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
  4. case let .qrCode(productCode):
  5. print("QR code: \(productCode).")
  6. }
  7. // prints "QR code: ABCDEFGHIJKLMNOP."


生の値


関連する値 のバーコードの例では、列挙型の case が、異なる型の関連する値を格納することを宣言できる方法を示しました。関連する値の代わりに、列挙型の case はすべて同じ型の (生の値 と呼ばれる)、デフォルト値で、事前入力できます。


ここでは名前の付いた列挙型の case と一緒に生の ASCII 値を格納する例を示します。


  1. enum ASCIIControlCharacter: Character {
  2. case tab = "\t"
  3. case lineFeed = "\n"
  4. case carriageReturn = "\r"
  5. }


ここでは、ASCIIControlCharacter と言う列挙型の生の値は、Character 型であると定義されており、より一般的な ASCII 制御文字の一部に設定されています。Character 値は、文字列と文字 で説明されています。


生の値は、文字列、文字、または整数、浮動小数点数型のいずれかです。それぞれの生の値は、その列挙型の宣言内で一意でなければなりません。


注意: 生の値は関連する値と同じでは ない です。上記の3つの ASCII コードのように、コード内で列挙型を最初に定義する際に生の値はあらかじめ入力した値に設定されます。特定の列挙型 case の生の値は常に同じです。関連する値は、列挙型の case の一つに基づいて、新しい定数または変数を作成するときに設定され、作成するたびに異なる場合がありえます。


暗黙に割り当てられた生の値


整数または文字列の生の値を格納する列挙型で作業しているときは、明示的に各 case の生の値を割り当てる必要はありません。割り当てない場合には、Swift は自動的に値を割り当てます。


例えば、整数が生の値に使用されている場合、各 case の暗黙の値は前の case より一つ多くなります。最初の case が、値を設定されていない場合は、その値は 0 です。


以下の列挙型は、太陽からの各惑星の順序を表す整数の生の値で、以前の Planet 列挙型の洗練されたものです。


  1. enum Planet: Int {
  2. case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
  3. }


上記の例では、Planet.mercury は明示的な生の値 1 を持ち、Planet.venus は暗黙的な生の値 2 を持っており、などなどです。


文字列が生の値に使用される場合、各 case の暗黙の値は、その case の名前のテキストです。


以下の列挙型では、各方向の名前を表す文字列の生の値を持つ、以前の CompassPoint 列挙型の洗練したものを示します。


  1. enum CompassPoint: String {
  2. case north, south, east, west
  3. }


上記の例では、CompassPoint.south は暗黙の生の値 "south" を持っており、などなどです。


その rawValue プロパティを持つ列挙型の case の生の値にアクセスできます。


  1. let earthsOrder = Planet.earth.rawValue
  2. // earthsOrder is 3
  3. let sunsetDirection = CompassPoint.west.rawValue
  4. // sunsetDirection is "west"


生の値からの初期化


生の値の型で列挙型を定義した場合、列挙型は生の値の型の値を(rawValue というパラメータとして)取るイニシャライザを自動的に受け取り、列挙型 の case か nil のいずれかを返します。列挙型の新しいインスタンスを作成しようとする時、このイニシャライザを使用できます。


以下の例では、その生の 7 の値から天王星 (Uranus) を識別します。


  1. let possiblePlanet = Planet(rawValue: 7)
  2. // possiblePlanet is of type Planet? and equals Planet.Uranus


すべての可能性のある Int 値が、しかしながら、一致する惑星(planet) を見つけるわけではありません。このため、生の値のイニシャライザは常に optional の列挙型の case を返します。上記の例では、possiblePlanetPlanet? 型、または "optional の Planet " です。


注意: 必ずしもすべての生の値が列挙型の case を返さないので、生の値のイニシャライザは、failable(失敗可能) イニシャライザです。詳細については、失敗可能イニシャライザ を参照してください。


11 の位置の惑星を見つけようとすると、生の値のイニシャライザによって返される optional の Planet の値は nil になります。


  1. let positionToFind = 11
  2. if let somePlanet = Planet(rawValue: positionToFind) {
  3. switch somePlanet {
  4. case .earth:
  5. print("Mostly harmless")
  6. default:
  7. print("Not a safe place for humans")
  8. }
  9. } else {
  10. print("There isn't a planet at position \(positionToFind)")
  11. }
  12. // prints "There isn't a planet at position 11"


この例では、11 の生の値で planet にアクセスしようとする optional の結合を使用しています。if let somePlanet = Planet(rawValue: 11) の文は、optional の Planet を作成し、それが取得できるなら、その optional の Planet の値に somePlanet を設定します。この場合には、11 の位置で planet を取得することは不可能なので、else の分岐が代わりに実行されます。



再帰的な列挙型


再帰的な列挙型 は、一つ以上の列挙型の case に関連した値として列挙型の別のインスタンスを持つ列挙型です。列挙型の case はその前に indirect を書くことにより、間接に必要な層を挿入するようにコンパイラに指示して、再帰的であることを示します。


例えば、ここで単純な算術式を格納する列挙型を挙げます。


  1. enum ArithmeticExpression {
  2. case number(Int)
  3. indirect case addition(ArithmeticExpression, ArithmeticExpression)
  4. indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
  5. }


また、列挙型の開始前に、indirect を書くこともでき、関連した値を持つ列挙型のすべての case で間接化を有効にすることもできます。


  1. indirect enum ArithmeticExpression {
  2. case number(Int)
  3. case addition(ArithmeticExpression, ArithmeticExpression)
  4. case multiplication(ArithmeticExpression, ArithmeticExpression)
  5. }


この列挙型は、算術式を 3 種類格納できます:プレーンな数、2つの式の加算、2つの式の乗算です。 additionmultiplication の case は、数式でもある関連した値を持っており、これらの関連した値は入れ子にした式にする事を可能にしています。たとえば、式 (5 + 4) * 2 は、乗算の右辺の数字や乗算の左辺に別の式を持っています。データが入れ子にされているので、データを格納するために使用される列挙型も、入れ子をサポートする必要があり、これはこの列挙型は再帰的である必要があることを意味します。以下のコードは ArithmeticExpression の再帰的な列挙型が (5 + 4) * 2 のために作成されている事を示しています。


  1. let five = ArithmeticExpression.number(5)
  2. let four = ArithmeticExpression.number(4)
  3. let sum = ArithmeticExpression.addition(five, four)
  4. let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))


再帰関数は再帰構造を持つデータを操作するための簡単な方法です。例えば、ここで算術式を評価する関数を挙げます。


  1. func evaluate(_ expression: ArithmeticExpression) -> Int {
  2. switch expression {
  3. case let .number(value):
  4. return value
  5. case let .addition(left, right):
  6. return evaluate(left) + evaluate(right)
  7. case let .multiplication(left, right):
  8. return evaluate(left) * evaluate(right)
  9. }
  10. }
  11. print(evaluate(product))
  12. // Prints "18"


この関数は、関連した値を単純に返すことで、プレーンな数字を評価します。これは、左辺の式を評価し、右辺の式を評価し、それらを追加したり、それらを乗算して、加算または乗算を評価します。


前:クロージャ 次:構造体とクラス
















トップへ












トップへ












トップへ












トップへ
目次
Xcode の新機能

Swift について
Swift と Cocoa と Objective-C (obsolete)
Swift Blog より (obsolete)

SwiftLogo
  • Swift 5.8 全メニュー


  • Swift へようこそ
  • Swift について
  • Swift 言語のガイド
  • Swift の基本
  • 基本演算子
  • 文字列と文字
  • コレクション型
  • フロー制御
  • 関数
  • クロージャ
  • 列挙型
  • 構造体とクラス
  • プロパティ
  • メソッド
  • サブスクリプト
  • 継承
  • 初期化
  • デイニシャライザ
  • Optional の連鎖
  • エラー処理
  • 同時実行
  • 型キャスト
  • ネストした型
  • 拡張機能
  • プロトコル
  • ジェネリック(汎用)
  • 不透明な型
  • 自動参照カウント
  • メモリの安全性
  • アクセス制御
  • 高度な演算子

  • 言語リファレンス

  • マニュアルの変更履歴













  • トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ