Swift 뿌수기 - Nested Types

Wonbi·2022년 8월 31일
2

Swift 뿌수기

목록 보기
7/12

✅학습 내용

💎 중첩 타입

Enumerations are often created to support a specific class or structure’s functionality. Similarly, it can be convenient to define utility classes and structures purely for use within the context of a more complex type. To accomplish this, Swift enables you to define nested types, whereby you nest supporting enumerations, classes, and structures within the definition of the type they support.

  • 열거체는 종종 특정 클래스나 구조체의 기능을 지원하고자 생성합니다. 이와 비슷하게, 순전히 더 복잡한 타입 안에서만 사용할 보조 클래스 및 구조체를 정의한다면 편리할 수 있습니다. 이를 해내고자, 스위프트는 지원할 타입의 정의 안에 지원용 열거체, 클래스, 및 구조체를 중첩하는 것으로, 중첩 타입 (nested types) 을 정의할 수 있게 합니다.

  • 다른 차입 안에 타입을 중첩하려면 지원할 타입의 바깥 중괄호{ 안에 타입의 정의를 작성한다. 필요한 만큼 많은 수준의 타입을 중첩할 수 있다.

✏️ 중첩 타입의 실제 사례

  • 아래 예제는, 블랙잭 게임 에서 사용할 트럼프 카드를 모델링하는, BlackjackCard라는 구조체를 정의한다. BlackjackCard 구조체는 SuitRank 라는 두 개의 중첩 열거체 타입을 담고 있다.

  • 블랙잭의 에이스 카드는 1 이나 11중 어느 하나의 값을 가진다. Rank 열거형 안에 중첩한 Values 라는 구조체로 이런 특징을 나타낸다.

struct BlackjackCard {

  // 중첩 Suit 열거형
  enum Suit: Character {
    case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
  }

  // 중첩 Rank 열거형
  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 의 프로퍼티 및 메소드
  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 원시 값 (rawValue) 과, 일반 트럼프 카드의 네 가지 패(모양)를 함께 설명한다.

  • Rank 열거형은 자신의 카드(숫자) 값을 나타내는 Int 원시 값과, 트럼프 카드에서 가능한 13 개의 끗수를 함께 설명한다. (잭 (Jack), 퀸 (Queen), 킹 (King), 및 에이스 (Ace) 카드에선 이 Int 원시 값을 사용하지 않는다.)

  • 위에서 언급한 것처럼, Rank 열거형은 자신만의 Values 라는 더 중첩된 구조체를 정의한다. 이 구조체는 대부분의 카드엔 하나의 값만 있지만, 에이스 카드엔 두 개의 값이 있다는 사실을 은닉한다. Values 구조체는 두 개의 프로퍼티를 정의하여 이를 나타낸다.
    1. first 프로퍼티: 타입은 Int

    1. second 프로퍼티: 타입은 Int?, 또는 “옵셔널 Int
  • RankValues 구조체 인스턴스를 반환하는 values 연산 프로퍼티도 정의한다. 이 연산 프로퍼티는 카드의 끗수를 고려하여 자신의 끗수에 기초한 적절한 값으로 새로운 Values 인스턴스를 초기화한다. jack, queen, king, 및 ace 면 특수한 값을 사용한다. 숫자 카드면 끗수의 Int 원시 값을 사용한다.

  • BlackjackCard 구조체 그 자체도 ranksuit 라는 두 프로퍼티를 가진다. description 이라는 연산 프로퍼티도 정의하는데, 이는 ranksuit 에 저장한 값을 사용하여 카드 이름과 값의 설명을 제작한다. description 프로퍼티는 옵셔널 바인딩을 사용하여 두 번째 값이 있는 지 검사하고, 값이 있는 경우 그 두 번째 값의 세부적인 추가 설명을 집어 넣는다.

  • BlackjackCard는 자신만의 이니셜라이저가 없는 구조체이기 때문에 Memberwise Initializers for Structure Types 에서 설명한 것처럼 암시적인 멤버 이니셜라이저를 가진다. 이 초기자를 사용하여 theAceOfSpades 라는 새로운 상수를 초기화할 수 있다.

let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
print("theAceOfSpades: \(theAceOfSpades.description)")
// "theAceOfSpades: suit is ♠, value is 1 or 11" 를 인쇄함
  • RankSuitBlackjackCard 안에 중첩되어 있을지라도 이 타입들은 상황으로 추론할 수 있어서 (.ace 와 .spades 라는) 자신의 case 이름 만으로도 이 인스턴스의 초기화가 열거형 case를 참조할 수 있다. 위 예제에선, 스페이드 에이스엔 1 또는 11 의 값이 있음을 description 프로퍼티가 올바르게 알려준다.

✏️ 중첩 타입 참조하기

  • 자신을 정의한 곳 밖에서 중첩 타입을 사용하려면, 그 이름에 자신을 중첩한 타입의 이름을 접두사로 붙인다.
let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
// heartsSymbol 은 "♡" 임

0개의 댓글