> For the complete documentation index, see [llms.txt](https://bbiguduk.gitbook.io/swift/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bbiguduk.gitbook.io/swift/language-guide-1/nested-types.md).

# 중첩 타입 (Nested Types)

{% hint style="info" %}
📢 **공지**\
이 문서는 더 이상 업데이트되지 않습니다.\
아래 새로운 URL로 업데이트 되었으니, 새로운 URL로 접속해 주세요.\
[Swift Book Korean](https://bbiguduk.github.io/swift-book-korean/documentation/tsplk/)
{% endhint %}

## 중첩 타입 (Nested Types)

타입의 범위 내에 다른 타입을 정의합니다.

열거형은 특정 클래스나 구조체의 기능을 지원하기 위해 생성합니다. 유사하게 더 복잡한 타입의 컨텍스트 내에서 사용하기 위해 유틸리티 구조체와 일반적으로 특정 타입과 함께 사용되는 프로토콜을 정의하는 것이 편리할 수 있습니다. 이를 위해 Swift는 \*중첩 타입(nested types)\*을 정의할 수 있으며, 지원하는 타입의 정의 내에서 열거형, 구조체, 프로토콜과 같은 타입을 중첩할 수 있습니다.

다른 타입 내에서 타입을 중첩하려면 지원하는 타입의 외부 중괄호 내에 정의를 작성해야 합니다. 타입은 필요에 따라 원하는 만큼 여러 단계로 중첩할 수 있습니다.

### 중첩 타입의 동작 (Nested Types in Action)

아래의 예시는 블랙잭 게임에서 사용되는 카드 게임을 모델링하는 `BlackjackCard`라는 구조체를 정의합니다. `BlackjackCard` 구조체는 `Suit`와 `Rank`라는 두 중첩된 열거형을 포함합니다.

블랙잭에서 에이스 카드의 값은 1이나 11입니다. 이러한 특징은 `Rank` 열거형 내에 중첩된 `Values`라는 구조체로 나타냅니다:

```swift
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` 열거형은 기호를 나타내기 위해 `Character` 타입을 원시값으로 네 가지 일반적인 카드 모양을 나타냅니다.

`Rank` 열거형은 카드 값을 나타내기 위해 `Int` 타입을 원시값으로 가능한 13가지 카드 순위를 나타냅니다. (이 `Int` 타입의 원시값은 Jack, Queen, King, Ace 카드에는 사용되지 않습니다.)

위에서 말했듯이 `Rank` 열거형은 `Values`라는 자신의 중첩된 구조체를 더 정의합니다. 이 구조체는 대부분의 카드는 하나의 값을 가지지만 에이스 카드는 두 값을 가지는 사실을 캡슐화합니다. `Values` 구조체는 다음과 같이 두 프로퍼티를 정의합니다:

* `Int` 타입의 `first`
* `Int?`나 "옵셔널 `Int`" 타입의 `second`

`Rank`는 `Values` 구조체의 인스턴스를 반환하는 `values`라는 연산 프로퍼티도 정의합니다. 이 연산 프로퍼티는 카드의 순위를 고려하고 그 순위를 기반으로 적절한 값으로 새로운 `Values` 인스턴스를 초기화합니다. `jack`, `queen`, `king`, `ace`에 대한 특별한 값을 사용합니다. 숫자 카드에 대해서는 순위의 `Int` 타입의 원시값을 사용합니다.

`BlackjackCard` 구조체는 `rank`와 `suit`의 두 프로퍼티를 가지고 있습니다. 이름과 카드의 값 설명을 만들기 위해 `rank`와 `suit`에 저장된 값을 사용하는 `description`이라는 연산 프로퍼티도 정의합니다. `description` 프로퍼티는 화면에 표시하기 위해 두 번째 값이 있는지 확인하고 있으면, 두 번째 값에 대해 상세 설명을 추가합니다.

`BlackjackCard`는 커스텀 이니셜라이저가 없는 구조체이기 때문에, [구조체 타입의 멤버와이즈 이니셜라이저 (Memberwise Initializers for Structure Types)](https://bbiguduk.gitbook.io/swift/language-guide-1/pages/-MHvWaCeiHryQnUz0937#구조체-타입의-멤버와이즈-이니셜라이저-memberwise-initializers-for-structure-types)에서 설명했듯이 암시적 멤버별 이니셜라이저를 가지고 있습니다. `theAceOfSpades`라는 새로운 상수를 초기화하기 위해 이니셜라이저를 사용할 수 있습니다:

```swift
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`)만으로 열거형 케이스를 참조할 수 있습니다. 위의 예시에서 `description` 프로퍼티는 스페이드의 에이스는 `1`이나 `11`의 값을 가지고 있다고 올바르게 보여줍니다.

### 중첩 타입 참조 (Referring to Nested Types)

중첩 타입을 그 정의된 범위 밖에서 사용하려면 그 타입이 중첩ㅚㄴ 외부 타입의 이름을 접두사로 붙여야 합니다:

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

위의 예시에서 `Suit`, `Rank`, `Values`의 이름은 정의된 컨텍스트에 따라 자연스럽게 규정되기 때문에 이름을 의도적으로 짧게 유지할 수 있습니다.
