Enumerations 列挙

An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code. 列挙は、一群の関連した値のための共通の型を定義して、それらの値を型安全な方法であなたのコード内で扱えるようにします。

If you are familiar with C, you will know that C enumerations assign related names to a set of integer values. Enumerations in Swift are much more flexible, and don’t have to provide a value for each case of the enumeration. If a value (known as a raw value) is provided for each enumeration case, the value can be a string, a character, or a value of any integer or floating-point type. あなたがCに精通しているならば、あなたはCの列挙がひとまとめの整数値それぞれに対して関連した名前を割り当てるということを知っています。スウィフトの列挙は、ずっと柔軟で、列挙のケース節の各々に値を与える必要はありません。値(rawの値として知られるもの)が列挙のケース節の各々のために提供されている場合には、その値は文字列、文字、またはあらゆる整数または浮動小数点型の値であることができます。

Alternatively, enumeration cases can specify associated values of any type to be stored along with each different case value, much as unions or variants do in other languages. You can define a common set of related cases as part of one enumeration, each of which has a different set of values of appropriate types associated with it. 代わりに、列挙ケース節は、ほとんど他の言語における共用体型やバリアント型がするように、それぞれ異なるケース節の値と一緒に格納されるために、あらゆる型の関連値を指定することが出来ます。あなたは、1つの列挙の一部として、関連したケース節のよくある集合を定義することができます、そのそれぞれはそれと結びつけられる適切な型の値の集合をそれぞれ別に持ちます。

Enumerations in Swift are first-class types in their own right. They adopt many features traditionally supported only by classes, such as computed properties to provide additional information about the enumeration’s current value, and instance methods to provide functionality related to the values the enumeration represents. Enumerations can also define initializers to provide an initial case value; can be extended to expand their functionality beyond their original implementation; and can conform to protocols to provide standard functionality. スウィフトの列挙は、れっきとした第一級の型です。それらはクラスによってのみ伝統的に支えられる多くの特徴を採用します、例えば列挙の現在の値に関する追加の情報を提供する計算プロパティ、そして、列挙が表す値に関連した機能性を提供するインスタンスメソッドなど。列挙は、さらに、最初のケース節値を提供するためにイニシャライザを定義することができます;それらの本来の実装を越えてそれらの機能性を広げるために拡張されることができます;そして、標準の機能性を提供するためにプロトコルに準拠することができます。

For more about these capabilities, see Properties, Methods, Initialization, Extensions, and Protocols. これらの能力に関する詳細は、プロパティメソッド初期化拡張、そしてプロトコルを見てください。

Enumeration Syntax 列挙構文

You introduce enumerations with the enum keyword and place their entire definition within a pair of braces: あなたは、列挙をenumキーワードで始めて、一対の波括弧の内側にそれらの全ての定義を置きます:

  1. enum SomeEnumeration {
  2. // enumeration definition goes here(列挙定義がここにきます)
  3. }

Here’s an example for the four main points of a compass: ここに、コンパスの主な4方位のための例があります:

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

The values defined in an enumeration (such as north, south, east, and west) are its enumeration cases. You use the case keyword to introduce new enumeration cases. 列挙で定義される値(例えばnorthsoutheast、そしてwest)は、それの列挙ケース節です。あなたはcaseキーワードを使って、新しい列挙ケース節を導入することができます。

Note 注意

Swift enumeration cases don’t have an integer value set by default, unlike languages like C and Objective-C. In the CompassPoint example above, north, south, east and west don’t implicitly equal 0, 1, 2 and 3. Instead, the different enumeration cases are values in their own right, with an explicitly defined type of CompassPoint. スウィフト列挙は、CおよびObjective-Cのような言語と違い、初期状態で設定される整数値を持ちません。上のCompassPoint例で、northsoutheastそしてwestは、暗黙のうちに012そして3に等しくはありません。その代わりに、異なる列挙ケース節それらは、ある明示的に定義されたCompassPointの型を持つ、自分だけのものである値です。

Multiple cases can appear on a single line, separated by commas: 複数のケース節は、コンマで区切られて、ただ1つの行に現れることができます:

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

Each enumeration definition defines a new type. Like other types in Swift, their names (such as CompassPoint and Planet) start with a capital letter. Give enumeration types singular rather than plural names, so that they read as self-evident: 各列挙定義は、ある新しい型を定義します。スウィフトにおける他の型のように、それらの名前(例えばCompassPointおよびPlanet)は、大文字から始まります。列挙型に複数形よりむしろ単数形の名前を与えてください、わかりきったことという印象を受けるので:

  1. var directionToHead = CompassPoint.west

The type of directionToHead is inferred when it’s initialized with one of the possible values of CompassPoint. Once directionToHead is declared as a CompassPoint, you can set it to a different CompassPoint value using a shorter dot syntax: directionToHeadの型は、それがCompassPointの可能な値のうちの1つで初期化されるとき、推論されます。一旦directionToHeadが、あるCompassPointとして宣言されるならば、あなたはそれをより短いドット構文を使って、異なるCompassPoint値に設定することができます:

  1. directionToHead = .east

The type of directionToHead is already known, and so you can drop the type when setting its value. This makes for highly readable code when working with explicitly typed enumeration values. directionToHeadの型はすでに知られています、それでその値を設定するとき、あなたは型を省くことができます。これは、明示的に型指定された列挙値を扱う場合に、非常に可読性の高いコードにします。

Matching Enumeration Values with a Switch Statement 列挙値をスイッチ文で照合する

You can match individual enumeration values with a switch statement: あなたは、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"(「ペンギンに気をつけろ」を出力します)

You can read this code as: あなたは、このコードを次のように読むことができます:

“Consider the value of directionToHead. In the case where it equals .north, print "Lots of planets have a north". In the case where it equals .south, print "Watch out for penguins".” directionToHeadの値を考慮する。それが.northに等しい場合には、"Lots of planets have a north"を出力する。それが.southに等しい場合には、"Watch out for penguins"を出力する。」

…and so on. …などなど。

As described in Control Flow, a switch statement must be exhaustive when considering an enumeration’s cases. If the case for .west is omitted, this code doesn’t compile, because it doesn’t consider the complete list of CompassPoint cases. Requiring exhaustiveness ensures that enumeration cases aren’t accidentally omitted. 制御の流れで記述されるように、switch文は列挙のケース節を考慮するとき、徹底的でなければなりません。.westのためのcaseが省略されるならば、このコードはコンパイルしません、なぜなら、それがCompassPointのケース節の完全なリストを考慮しないからです。網羅性を要求することは、列挙ケース節のどれかがうっかり書き落とされないことを確実にします。

When it isn’t appropriate to provide a case for every enumeration case, you can provide a default case to cover any cases that aren’t addressed explicitly: すべての列挙ケース節にcaseを提供することが妥当でないとき、あなたは明確に指定されないあらゆる場合を扱うためにdefaultケース節を提供することができます:

  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"(「おおむね無害」を出力します)

Iterating over Enumeration Cases 列挙ケース節の全てにわたって反復する

For some enumerations, it’s useful to have a collection of all of that enumeration’s cases. You enable this by writing : CaseIterable after the enumeration’s name. Swift exposes a collection of all the cases as an allCases property of the enumeration type. Here’s an example: いくつかの列挙に対して、その列挙の持つケース節の全てからなるコレクションを持つことは役に立ちます。あなたは、これを: CaseIterableを列挙の名前の後に書くことによって可能にします。スウィフトは、ケース節すべてからなるコレクションを、列挙型の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"

In the example above, you write Beverage.allCases to access a collection that contains all of the cases of the Beverage enumeration. You can use allCases like any other collection—the collection’s elements are instances of the enumeration type, so in this case they’re Beverage values. The example above counts how many cases there are, and the example below uses a for-in loop to iterate over all the cases. 上の例において、あなたはBeverage.allCasesを書いて、Beverage列挙のケース節の全てを含むコレクションにアクセスします。あなたは、allCasesを何らかの他のコレクションと同様に使うことができます — コレクションの持つ要素は列挙型のインスタンスです、それでこの場合においてそれらはBeverage値です。上の例は、どのくらい多くのケース節があるか数えます、そして下の例は、for-inループを使って全てのケース節にわたって反復します。

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

The syntax used in the examples above marks the enumeration as conforming to the CaseIterable protocol. For information about protocols, see Protocols. 上の例において使われる構文は、列挙をCaseIterableプロトコルに準拠するように印します。プロトコルについての情報として、プロトコルを見てください。

Associated Values 関連値

The examples in the previous section show how the cases of an enumeration are a defined (and typed) value in their own right. You can set a constant or variable to Planet.earth, and check for this value later. However, it’s sometimes useful to be able to store values of other types alongside these case values. This additional information is called an associated value, and it varies each time you use that case as a value in your code. 前の節での例は、列挙のケース節がどのように自分だけで定義された(そして型付けされた)値であるかについて示します。あなたは、定数または変数をPlanet.earthに設定することができて、後でその値について調べることができます。しかし、他の型の値をこれらのケース節値の傍らに格納することができることは、時々役に立ちます。この追加的情報は、関連値と呼ばれます、そしてそれは、あなたがそのケース節をある値としてあなたのコードにおいて使うたびに変化します。

You can define Swift enumerations to store associated values of any given type, and the value types can be different for each case of the enumeration if needed. Enumerations similar to these are known as discriminated unions, tagged unions, or variants in other programming languages. あなたはスウィフト列挙を、どんな与えられた型の関連値でも格納するように定義することができます、そして値の型は列挙のケース節それぞれで異なっていることが可能です。これに似ている列挙は、他のプログラミング言語で判別共用体タグ付き共用体、またはバリアントとして知られています。

For example, suppose an inventory tracking system needs to track products by two different types of barcode. Some products are labeled with 1D barcodes in UPC format, which uses the numbers 0 to 9. Each barcode has a number system digit, followed by five manufacturer code digits and five product code digits. These are followed by a check digit to verify that the code has been scanned correctly: 例えば、ある在庫追跡システムが、2つの異なる型のバーコードによって製品を追跡する必要があると思ってください。ある製品はUPC形式の一次元バーコードでラベルをつけられます、それは0から9までの数字を使います。各バーコードは、1つの「ナンバーシステム」桁、それに続く5桁の「製造者コード」そして5桁の「商品コード」を持ちます。これらの後にコードが正しくスキャンされたことを確認するための1つの「チェック」桁が続きます:

../_images/barcode_UPC_2x.png

Other products are labeled with 2D barcodes in QR code format, which can use any ISO 8859-1 character and can encode a string up to 2,953 characters long: 別の製品はQRコード形式の二次元バーコードでラベルをつけられます、それはどんなISO 8859-1の文字でも使うことができて、2,953文字までの長さの文字列をコード化することができます:

../_images/barcode_QR_2x.png

It’s convenient for an inventory tracking system to store UPC barcodes as a tuple of four integers, and QR code barcodes as a string of any length. UPCバーコードを4つの整数のタプルとして、そしてQRコード・バーコードを任意の長さの文字列として格納できるのは、在庫追跡システムにとって便利です。

In Swift, an enumeration to define product barcodes of either type might look like this: スウィフトにおいて、両方の種類の製品バーコードを定義する列挙は、これのように見えるかもしれません:

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

This can be read as: これは、次のように解釈されることができます:

“Define an enumeration type called Barcode, which can take either a value of upc with an associated value of type (Int, Int, Int, Int), or a value of qrCode with an associated value of type String.” Barcodeと呼ばれる列挙型を定義します、それはupcの値で型(IntIntIntInt)の関連値をもつ、またはqrCodeの値で型Stringの関連値をもつものをとることができます。」

This definition doesn’t provide any actual Int or String values—it just defines the type of associated values that Barcode constants and variables can store when they’re equal to Barcode.upc or Barcode.qrCode. この定義は、何ら実際のIntまたはString値を提供しません ― それは、ただ単に関連値のを定義します、それは、Barcode定数と変数がBarcode.upcもしくはBarcode.qrCodeに等しいときに格納できる型です。

You can then create new barcodes using either type: あなたはそれから新しいバーコードをどちらかの型を使って作成できます:

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

This example creates a new variable called productBarcode and assigns it a value of Barcode.upc with an associated tuple value of (8, 85909, 51226, 3). この例は、productBarcodeと呼ばれる新しい変数をつくって、それにあるひとつのBarcode.upcの値を関連したタプル値(8, 85909, 51226, 3)とともに代入します。

You can assign the same product a different type of barcode: あなたは、同じ商品を異なる型のバーゴードに割り当てることができます:

  1. productBarcode = .qrCode("ABCDEFGHIJKLMNOP")

At this point, the original Barcode.upc and its integer values are replaced by the new Barcode.qrCode and its string value. Constants and variables of type Barcode can store either a .upc or a .qrCode (together with their associated values), but they can store only one of them at any given time. この点で、最初のBarcode.upcおよびその整数値は、新しいBarcode.qrCodeおよびその文字列値と取り替えられます。型Barcodeの定数と変数は、.upcまたは.qrCodeのどちらでも(それらの関連値と共に)格納することができます、しかしそれらはどんな時でもそれらの1つを格納することだけができます。

You can check the different barcode types using a switch statement, similar to the example in Matching Enumeration Values with a Switch Statement. This time, however, the associated values are extracted as part of the switch statement. You extract each associated value as a constant (with the let prefix) or a variable (with the var prefix) for use within the switch case’s body: あなたは、異なるバーコード型それらを、列挙値をスイッチ文で照合するでの例に似たあるスイッチ文を使って調べることができます。今度は、しかし、関連値がスイッチ文の一部として抽出されます。あなたは、関連値それぞれを定数(let接頭辞を使って)または変数(var接頭辞を使って)としてswitchのケース節の本文内で使用するために抽出します:

  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."(「QRコード:ABCDEFGHIJKLMNOP。」を出力します)

If all of the associated values for an enumeration case are extracted as constants, or if all are extracted as variables, you can place a single var or let annotation before the case name, for brevity: 列挙ケース節の関連値の全てが定数として抽出されるならば、または全てが変数として抽出されるならば、あなたは簡潔にvarまたはlet注釈1つだけをケース節名の前に置くことができます:

  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."(「QRコード:ABCDEFGHIJKLMNOP。」を出力します)

Raw Values 生の値

The barcode example in Associated Values shows how cases of an enumeration can declare that they store associated values of different types. As an alternative to associated values, enumeration cases can come prepopulated with default values (called raw values), which are all of the same type. 関連値におけるバーコード例は、それらが異なる型の関連値を格納することを、ある列挙のケース節それらがどのように宣言可能かを示します。関連値に代わるものとして、列挙ケース節は全て同じ型の(生の値と呼ばれる)初期値があらかじめ入れられた状態であることが出来ます。

Here’s an example that stores raw ASCII values alongside named enumeration cases: 指定した列挙ケース節の傍らに生のASCII値を格納する例は、ここにあります:

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

Here, the raw values for an enumeration called ASCIIControlCharacter are defined to be of type Character, and are set to some of the more common ASCII control characters. Character values are described in Strings and Characters. ここでは、ASCIIControlCharacterと呼ばれる列挙に対する生の値は、型Characterであると定義されて、たいへんありふれたASCII制御文字のいくつかに設定されます。Character値は文字列と文字で記述されます。

Raw values can be strings, characters, or any of the integer or floating-point number types. Each raw value must be unique within its enumeration declaration. 生の値は、文字列、文字、または何らかの整数や浮動小数点数型であることができます。生の値それぞれは、その列挙宣言の範囲内で固有でなければなりません。

Note 注意

Raw values are not the same as associated values. Raw values are set to prepopulated values when you first define the enumeration in your code, like the three ASCII codes above. The raw value for a particular enumeration case is always the same. Associated values are set when you create a new constant or variable based on one of the enumeration’s cases, and can be different each time you do so. 生の値は、関連値と同じものでない点に注意してください。生の値は、上の3つのASCIIコードの様に、あなたがあなたのコードにおいて最初に列挙を定義するとき、あらかじめ入れられた値に設定されます。特定の列挙ケース節のための生の値は、常に同じものです。関連値は、あなたが列挙のケース節のうちの1つに基づいて新しい定数または変数を作るときに設定されます、そしてあなたがそうするたびに違ったものにすることが出来ます。

Implicitly Assigned Raw Values 暗黙的に割り当てられる生の値

When you’re working with enumerations that store integer or string raw values, you don’t have to explicitly assign a raw value for each case. When you don’t, Swift automatically assigns the values for you. あなたが整数や文字列の生の値を格納する列挙を使って作業している時、あなたは各ケース節に生の値を明示的に割り当てる必要はありません。あなたがそうしない時は、スウィフトはあなたの代わりに自動的に値を割り当てます。

For example, when integers are used for raw values, the implicit value for each case is one more than the previous case. If the first case doesn’t have a value set, its value is 0. 例えば、整数が生の値のために使われるとき、各ケース節に対する暗黙の値は、その前のケース節よりも1つ多くなります。最初のケース節が値を設定されないならば、それの値は0です。

The enumeration below is a refinement of the earlier Planet enumeration, with integer raw values to represent each planet’s order from the sun: 下の列挙は、以前のPlanet列挙の改良で、太陽からの各惑星の順番を表す整数の生の値をもちます:

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

In the example above, Planet.mercury has an explicit raw value of 1, Planet.venus has an implicit raw value of 2, and so on. 上の例において、Planet.mercuryは明示的な生の値の1を持ちます、Planet.venusは暗黙的な生の値の2を持ちます、等々。

When strings are used for raw values, the implicit value for each case is the text of that case’s name. 文字列が生の値のために使われる時、各ケース節のための暗黙的な値は、そのケース節の名前のテキストです。

The enumeration below is a refinement of the earlier CompassPoint enumeration, with string raw values to represent each direction’s name: 以下の列挙は、前のCompassPoint列挙の改良版で、各方位の名前を表す文字列の生の値を持ちます:

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

In the example above, CompassPoint.south has an implicit raw value of "south", and so on. 上の例において、CompassPoint.southは暗黙的な生の値の"south"をもちます、等々。

You access the raw value of an enumeration case with its rawValue property: ある列挙ケース節の生の値にそれのrawValueプロパティでアクセスしてください:

  1. let earthsOrder = Planet.earth.rawValue
  2. // earthsOrder is 3(earthsOrderは、3です)
  3. let sunsetDirection = CompassPoint.west.rawValue
  4. // sunsetDirection is "west"(sunsetDirectionは、「west」です)

Initializing from a Raw Value 生の値から初期化する

If you define an enumeration with a raw-value type, the enumeration automatically receives an initializer that takes a value of the raw value’s type (as a parameter called rawValue) and returns either an enumeration case or nil. You can use this initializer to try to create a new instance of the enumeration. あなたが列挙を「生の値」型を使って定義したならば、その列挙は生の値の方の値を(rawValueと呼ばれるパラメーターとして)とって、1つの列挙ケース節かnilのどちらかを返すイニシャライザを自動的に受け取ります。あなたは、このイニシャライザを使って、この列挙の新しいインスタンスを作成するように試みることができます。

This example identifies Uranus from its raw value of 7: この例は、その生の値の7からUranus(天王星)を特定します:

  1. let possiblePlanet = Planet(rawValue: 7)
  2. // possiblePlanet is of type Planet? and equals Planet.uranus(possiblePlanetは、型Planet?で、Planet.uranusに等しい)

Not all possible Int values will find a matching planet, however. Because of this, the raw value initializer always returns an optional enumeration case. In the example above, possiblePlanet is of type Planet?, or “optional Planet.” しかし、全ての可能なInt値が、適合する惑星を見つけるというわけでありません。そのため、生の値のイニシャライザは常にオプショナルの列挙ケース節を返します。上の例で、possiblePlanetは型Planet?、すなわち「オプショナルのPlanet」です。

Note 注意

The raw value initializer is a failable initializer, because not every raw value will return an enumeration case. For more information, see Failable Initializers. 生の値のイニシャライザは、失敗できるイニシャライザです、なぜなら、すべての生の値が列挙ケース節を返すわけではないからです。さらなる情報として、失敗できるイニシャライザを見てください。

If you try to find a planet with a position of 11, the optional Planet value returned by the raw value initializer will be nil: あなたが11の位置で惑星を見つけようとするならば、生の値のイニシャライザによって返されるオプショナルの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に惑星は存在しない」を出力します)

This example uses optional binding to try to access a planet with a raw value of 11. The statement if let somePlanet = Planet(rawValue: 11) creates an optional Planet, and sets somePlanet to the value of that optional Planet if it can be retrieved. In this case, it isn’t possible to retrieve a planet with a position of 11, and so the else branch is executed instead. この例は、11の生の値で惑星にアクセスすることを試みるためにオプショナル束縛を使います。文if let somePlanet = Planet(rawValue: 11)は、オプショナルのPlanetを作成して、それが取り出されることができるならば、somePlanetをそのオプショナルのPlanetのもつ値に設定します。この場合、11の位置で惑星を取り出すことは可能ではありません、それでelse分岐が代わりに実行されます。

Recursive Enumerations 再帰列挙

A recursive enumeration is an enumeration that has another instance of the enumeration as the associated value for one or more of the enumeration cases. You indicate that an enumeration case is recursive by writing indirect before it, which tells the compiler to insert the necessary layer of indirection. 再帰列挙は、1つ以上の列挙ケース節のための関連値としてその列挙の別のインスタンスを持つ列挙です。あなたは、ある列挙ケース節が再帰することをそれの前にindirectを書くことによって指し示します、それは、コンパイラに不可欠な間接参照の階層を差し入れるように伝えます。

For example, here is an enumeration that stores simple arithmetic expressions: 例えば、ここに単純な算術式を格納する列挙があります:

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

You can also write indirect before the beginning of the enumeration to enable indirection for all of the enumeration’s cases that have an associated value: あなたはまた、列挙の始まりの前にindirectを書くことで、列挙の持つケース節で関連値を持つもの全てに対して間接参照を可能にできます。

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

This enumeration can store three kinds of arithmetic expressions: a plain number, the addition of two expressions, and the multiplication of two expressions. The addition and multiplication cases have associated values that are also arithmetic expressions—these associated values make it possible to nest expressions. For example, the expression (5 + 4) * 2 has a number on the right-hand side of the multiplication and another expression on the left-hand side of the multiplication. Because the data is nested, the enumeration used to store the data also needs to support nesting—this means the enumeration needs to be recursive. The code below shows the ArithmeticExpression recursive enumeration being created for (5 + 4) * 2: この列挙は、3種類の算術式:普通の数字、2つの式の加算、そして2つの式の乗算を格納することができます。additionmultiplicationケース節は、それもまた算術式である関連値を持ちます—これらの関連値がそれを入れ子式可能なものにします。例えば、式(5 + 4) * 2は、1つの数を掛け算の右手側に、そして別の式を掛け算の左手側に持ちます。データが入れ子にされるため、データを格納するために使われる列挙もまた、入れ子をサポートする必要があります—これは列挙が再帰することを必要とするのを意味します。以下のコードは、(5 + 4) * 2に対して作成されている再帰列挙ArithmeticExpressionを示します:

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

A recursive function is a straightforward way to work with data that has a recursive structure. For example, here’s a function that evaluates an arithmetic expression: 再帰関数は、率直な方法で再帰構造を持つデータを扱います。例えば、ここに算術式の数値を求める関数があります:

  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"

This function evaluates a plain number by simply returning the associated value. It evaluates an addition or multiplication by evaluating the expression on the left-hand side, evaluating the expression on the right-hand side, and then adding them or multiplying them. この関数は、普通の数字を単に関連値を返すことによって評価します。それは加算や乗算を、左手側の式を評価し、右手側の式を評価して、それからそれらを加算や乗算することで評価します。

Closures クロージャ

Structures and Classes 構造体とクラス