見出し画像

Swiftでプログラミング-Nested Types

多くの場合、列挙体は特定のクラスまたは構造体の機能をサポートするために作成されます。 同様に、より複雑な型をコードの内側で使用することを目的にユーティリティクラスと構造体を定義すると便利な場合があります。 これを実現するために、Swiftではネストされた型を定義できます。これにより、サポートする列挙体、クラス、および構造体を、それらがサポートする型の定義を内側に書くことが出来ます。

別の型の内にネストするには、サポートする型の外側の中括弧内にその定義を記述します。 型は、必要な数だけネストできます。

Nested Types in Action

以下の例では、トランプゲーム、ブラックジャックをモデルに、ブラックジャックカードと呼ぶ構造体を定義しています。 構造体BlackjackCardには、SuitとRankと呼ばれる2つのネストされた列挙型が含まれています。

ブラックジャックでは、エースのカードの値は"1"または"11"です。 これは列挙体Rankに内包される形で構造体valuesとして定義されています。

    struct BlackjackCard {
       // nested Suit enumeration
       enum Suit: Character {
           case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
       }
       // nested Rank enumeration
       enum Rank: Int {
           case two = 2, three, four, five, six, seven, eight, nine, ten
           case jack, queen, king, ace
           struct Values {
               let first: Int, second: Int?
           }
           var values: Values {
               switch self {
               case .ace:
                   return Values(first: 1, second: 11)
               case .jack, .queen, .king:
                   return Values(first: 10, second: nil)
               default:
                   return Values(first: self.rawValue, second: nil)
               }
           }
       }
       // BlackjackCard properties and methods
       let rank: Rank, suit: Suit
       var description: String {
           var output = "suit is \(suit.rawValue),"
           output += " value is \(rank.values.first)"
           if let second = rank.values.second {
               output += " or \(second)"
           }
           return output
       }
   }

列挙体Suitは、4つの一般的なトランプカードと、それらのシンボルを表すRaw Value(値)を記述します。

列挙体Rankで、13種類のトランプを、それらの額面を表すInt値とRaw Value(値)を記述します。 (このRaw Value(値)、Int値は、ジャック、クイーン、キング、エースのカードには使用されません。)

上記のように、列挙体Rank挙は、Valuesと呼ばれる独自のネストされた構造体をさらに定義します。この構造体は、ほとんどのカードが1つの値を持っていてカプセル化していますが、エースカードは2つの値を持っています。 構造体Valuesは、これを表す2つのプロパティを定義します。

・first Int型
・second Int ?、または optional Int型

Rankは、構造体Valuesのインスタンスを返す計算プロパティ、valuesも定義します。この計算プロパティは、カードの順番を考慮し、その順番に基づいて適切な値で新しいValuesインスタンスを初期化します。ジャック、クイーン、キング、エースに特別な値を使用します。数値カードの場合、順番にRaw Value(値)、Int値を使用します。

構造体BlackjackCard自体には、rankとsuitの2つのプロパティがあります。また、descriptionと呼ばれる計算プロパティを定義します。これは、rankとsuitに格納されている値を使用して、カードの名前と値の説明を作成します。 descriptionプロパティは、オプションのバインディングを使用して、表示する2番目の値があるかどうかを確認し、ある場合は、その2番目の値に追加の説明の詳細を挿入します。

BlackjackCardはカスタム初期化子を持たない構造体であるためMemberwise initializerを使って初期化して、theAceOfSpadesと呼ばれる新しい定数を作ることができます。

   let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
   print("theAceOfSpades: \(theAceOfSpades.description)")
   // Prints "theAceOfSpades: suit is ♠, value is 1 or 11"

RankとSuitはBlackjackCard内にネストされていますが、それらの型は文脈から推測できるため、このインスタンスの初期化では、case名(.aceと.spades)のみで列挙ケースを参照できます。 上記の例では、descriptionプロパティは、Ace ofSpadesの値が1または11であることを正しく出力しています。

Referring to Nested Types

定義したところ以外でネストされた型を使用するには、その名前の前に、ネストされている型の名前を付けます。

    let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
   // heartsSymbol is "♡"

上記の例では、これにより、Suit、Rank、Valuesの名前を意図的に短くすることができます。Suit、Rank、Valuesは、自然に修飾されるように定義されています。

この記事が気に入ったらサポートをしてみませんか?