열거형은 특정 클래스나 구조체의 기능을 지원하기 위해 만들어지는 경우가 많다. 이와 비슷하게, 보다 복잡한 타입의 문맥에서 사용하기 위해 유틸리티 클래스나 구조체를 정의하는 게 편리할 수 있다. Swift는 이를 위해 중첩 타입(nested type)
을 정의할 수 있다. 열거형, 클래스, 구조체를 지원되는 타입의 정의 안에서 중첩시킬 수 있다.
한 유형을 다른 유형 안에 중첩시키려면 지원되는 타입의 외부 중괄호 안에 그것의 정의를 작성한다. 필요한 만큼 많은 단계로 타입을 중첩시킬 수 있다.
아래 예시는 BlackjackCard
구조체를 정의한다. BlackjackCard
구조체는 Suit
와 Rank
두 가지 중첩된 열거형 타입을 포함한다.
블랙잭에서 에이스 카드는 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
열거형은 네 가지 카드 모양을 심볼을 표현하는 raw 문자 값과 함께 묘사한다.
Rank
열거형은 실제 값을 표현하는 raw 정수 값과 함께 카드의 랭크를 묘사한다(이 정수 값은 잭, 퀸, 킹, 에이스 카드에는 사용되지 않는다).
앞서 언급한 것처럼, Rank
열거형은 그 안에 Values
중첩 구조체를 정의한다. 이 구조체는 대부분의 카드는 하나의 값을, 에이스 카드는 두 개의 값을 가질 수 있다는 사실을 캡슐화한다. Values
구조체는 이를 표현하기 위해 first
와 second
두 프로퍼티를 선언한다.
Rank
는 계산 프로퍼티인 values
를 정의한다. 이는 Values
구조체의 인스턴스를 반환한다. 이 계산 프로퍼티는 카드의 랭크를 고려하고, 이를 기반으로 한 적절한 값으로 새로운 Values
인스턴스를 초기화 한다. 잭, 퀸, 킹, 에이스 카드를 위한 특별한 값을 사용한다.
BlackjackCard
구조체는 rank
와 suit
두 프로퍼티를 갖는다. desciption
계산 프로퍼티도 정의하는데, rank
와 suit
에 저장된 값을 사용해 카드의 이름과 값을 출력한다. 이 desciption
프로퍼티는 두 번째 값을 보여 줄 수 있는지 확인하기 위해 옵셔널 바인딩을 사용한다. 가능할 경우 두 번째 값에 대한 상세 정보를 추가한다.
BlackjackCard
구조체에 커스텀 이니셜라이저가 없기 때문에, 암시적인 멤버 이니셜라이저를 갖게 된다. theAceOfSpades
상수를 초기화하기 위해 이 이니셜라이저를 사용할 수 있다.
let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
print("theAceOfSpades: \(theAceOfSpades.description)")
// Prints "theAceOfSpades: suit is ♠, value is 1 or 11"
Rank
와 Suit
가 BlackjackCard
에 중첩된 것이더라도, 이들의 타입은 문맥으로부터 추론될 수 있다. 그리고 이 인스턴스의 초기화는 케이스 이름(.ace
와 .spades
)에 의해 열거형 케이스를 참조할 수 있다.
정의된 문맥 바깥에서 중첩 타입을 사용하기 위해 이름 앞에 중첩된 타입의 이름을 붙인다.
let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
// heartsSymbol is "♡"