공식 문서로 공부하는 Swift (18) - 중첩 타입

ci·2020년 5월 31일
1

Nested Types

열거형은 특정 클래스나 구조체의 기능을 지원하기 위해 만들어지는 경우가 많다. 이와 비슷하게, 보다 복잡한 타입의 문맥에서 사용하기 위해 유틸리티 클래스나 구조체를 정의하는 게 편리할 수 있다. Swift는 이를 위해 중첩 타입(nested type)을 정의할 수 있다. 열거형, 클래스, 구조체를 지원되는 타입의 정의 안에서 중첩시킬 수 있다.

한 유형을 다른 유형 안에 중첩시키려면 지원되는 타입의 외부 중괄호 안에 그것의 정의를 작성한다. 필요한 만큼 많은 단계로 타입을 중첩시킬 수 있다.



중첩 타입의 사용

아래 예시는 BlackjackCard 구조체를 정의한다. BlackjackCard 구조체는 SuitRank 두 가지 중첩된 열거형 타입을 포함한다.

블랙잭에서 에이스 카드는 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 구조체는 이를 표현하기 위해 firstsecond 두 프로퍼티를 선언한다.

Rank는 계산 프로퍼티인 values를 정의한다. 이는 Values 구조체의 인스턴스를 반환한다. 이 계산 프로퍼티는 카드의 랭크를 고려하고, 이를 기반으로 한 적절한 값으로 새로운 Values 인스턴스를 초기화 한다. 잭, 퀸, 킹, 에이스 카드를 위한 특별한 값을 사용한다.

BlackjackCard 구조체는 ranksuit 두 프로퍼티를 갖는다. desciption 계산 프로퍼티도 정의하는데, ranksuit에 저장된 값을 사용해 카드의 이름과 값을 출력한다. 이 desciption 프로퍼티는 두 번째 값을 보여 줄 수 있는지 확인하기 위해 옵셔널 바인딩을 사용한다. 가능할 경우 두 번째 값에 대한 상세 정보를 추가한다.


BlackjackCard 구조체에 커스텀 이니셜라이저가 없기 때문에, 암시적인 멤버 이니셜라이저를 갖게 된다. theAceOfSpades 상수를 초기화하기 위해 이 이니셜라이저를 사용할 수 있다.

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

RankSuitBlackjackCard에 중첩된 것이더라도, 이들의 타입은 문맥으로부터 추론될 수 있다. 그리고 이 인스턴스의 초기화는 케이스 이름(.ace.spades)에 의해 열거형 케이스를 참조할 수 있다.



중첩 타입 참조하기

정의된 문맥 바깥에서 중첩 타입을 사용하기 위해 이름 앞에 중첩된 타입의 이름을 붙인다.

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

0개의 댓글