티스토리 뷰

Swift 공식 가이드/Swift 3

Nested Types

찜토끼 2017. 3. 23. 00:28

Apple 제공 Swift 프로그래밍 가이드(3.0.1)의 Nested Types 부분을 공부하며 정리한 글입니다. 개인적인 생각도 조금 들어가있습니다.



들어가며

ENUM은 특정 클래스나 구조체의 기능functionality을 돕기 위해 생성되곤 한다. 이와 비슷하게, 복잡한 타입의 context에서는 유틸리티 클래스와 구조체를 정의하는 것이 편리하다. 이를 위해 nested type(중첩된 타입)이라는 것이 있다. 특정 타입의 정의 안에서 ENUM, 클래스, 구조체 등을 중첩하여 정의하는 방식으로 사용한다.

특정 타입의 정의를 둘러싼 대괄호({}) 안에서 새로운 타입을 중첩하여 정의할 수 있고, 원하는 만큼 중첩할 수 있다. (중첩 안의 중첩이 계속 가능하다는 말)


Nested Type 실제로 써보기

블랙잭 게임을 위한 BlackjackCard 구조체의 예제를 통하여 Nested Type을 살펴보자.

  • BlackjackCard 구조체 안에는 Suit와 Rank라는 nested ENUM이 있다.

  • Suit ENUM은 4가지 종류의 카드 무늬와 raw character 값을 표현한다.

  • Rank ENUM은 13 종류의 카드 랭크와 raw int 값을 표현한다. (단, 이 raw int값은 잭/퀸/킹/에이스 카드에는 사용되지 않음)

  • Rank ENUM 안에 중첩된 Values 라는 구조체는, 블랙잭에서 에이스 카드가 1 또는 11 의 값을 가질 수 있다는 룰을 반영한다. (* 블랙잭의 룰은 여기를 참조)
    대부분의 카드는 1개의 값을 가지지만 에이스 카드는 2개의 값 중 하나가 될 수 있다는 룰을 Values 구조체를 통해 캡슐화하고 있는 것이다. (따라서 Values 구조체는 Int와 Int? 프로퍼티를 가진다)

  • Rank ENUM은 values 라는 computed property도 정의하고 있다. 이 프로퍼티는 Values 구조체의 인스턴스를 리턴해준다. 일반적인 숫자카드의 경우에는 그에 해당하는 rank를 참조하고, 잭/퀸/킹/에이스 카드의 경우에는 special value를 사용한다.

struct BlackjackCard {
    
    // nested Suit ENUM
    enum Suit: Character {
        case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
    }
    
    // nested Rank ENUM
    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)
            }
        }
    }
    
    // 내부 프로퍼티 & 메서드
    let rank: Rank
    let suit: Suit
    
    var description: String {
        var output = "카드 무늬는 \(suit.rawValue),"
        output += " 값은 \(rank.values.first)"
        
        // 에이스 카드를 위해
        if let second = rank.values.second {
            output += " 또는 \(second)"
        }
        
        return output
    }
}


// Rank와 Suit ENUM은 BlackjackCard 안에 중첩되어 있지만
// 문맥으로부터 타입을 유추할 수 있기 때문에
// 아래처럼 case의 이름으로 초기화를 할 수 있다.
// (그리고 BlackjackCard는 custom initializer가 없으므로, 
// memberwise initializer 를 사용 가능하다.)
let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)

print(theAceOfSpades.description) // "카드 무늬는 ♠, 값은 1 또는 11"



Nested Type 참조하기

Nested type이 정의된 문맥 바깥에서 Nested type을 참조하려면 그 이름 앞에 자신을 중첩하고 있는 타입의 이름을 붙인다.

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


'Swift 공식 가이드 > Swift 3' 카테고리의 다른 글

Protocols (1)  (0) 2017.03.23
Extensions  (1) 2017.03.23
Type Casting  (0) 2017.03.23
Error Handling  (0) 2017.03.18
Optional Chaining  (0) 2017.03.18
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함