![見出し画像](https://assets.st-note.com/production/uploads/images/55202101/rectangle_large_type_2_fa7e1bb95219e5a85f58f07407d138f1.png?width=1200)
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は、自然に修飾されるように定義されています。