Swift基础 嵌套类型

翻译自:https://docs.swift.org/swift-book/LanguageGuide/NestedTypes.html

创建枚举通常是为了支持特定类或结构的功能。同样,可以方便地定义纯属实用程序类和结构,以便在更复杂类型的上下文中使用。为了做到这一点,Swift使您能够定义嵌套类型,从而在它们支持的类型的定义中嵌套支持枚举、类和结构。

要将类型嵌套在另一种类型中,请在它支持的类型的外部大括号中写入其定义。类型可以嵌套到所需的任意级别。

嵌套类型在行动

下面的示例定义了一个名为BlackjackCard结构,该结构模拟了二十一点游戏中使用的扑克牌。BlackjackCard结构包含两种嵌套枚举类型,称为SuitRank

在二十一点中,Ace卡的价值为1或11。此功能由一个名为Values结构表示,该结构嵌套在Rank枚举中:

  1. struct BlackjackCard {
  2. ​ // nested Suit enumeration
  3. ​ enum Suit: Character {
  4. ​ case spades = “♠”, hearts = “♡”, diamonds = “♢”, clubs = “♣”
  5. ​ }
  6. ​ // nested Rank enumeration
  7. ​ enum Rank: Int {
  8. ​ case two = 2, three, four, five, six, seven, eight, nine, ten
  9. ​ case jack, queen, king, ace
  10. ​ struct Values {
  11. ​ let first: Int, second: Int?
  12. ​ }
  13. ​ var values: Values {
  14. ​ switch self {
  15. ​ case .ace:
  16. ​ return Values(first: 1, second: 11)
  17. ​ case .jack, .queen, .king:
  18. ​ return Values(first: 10, second: nil)
  19. ​ default:
  20. ​ return Values(first: self.rawValue, second: nil)
  21. ​ }
  22. ​ }
  23. ​ }
  24. ​ // BlackjackCard properties and methods
  25. ​ let rank: Rank, suit: Suit
  26. ​ var description: String {
  27. ​ var output = “suit is (suit.rawValue),”
  28. ​ output += “ value is (rank.values.first)”
  29. ​ if let second = rank.values.second {
  30. ​ output += “ or (second)”
  31. ​ }
  32. ​ return output
  33. ​ }
  34. }

Suit枚举描述了四套常见的扑克牌套装,以及代表其符号的原始Character值。

Rank枚举描述了13个可能的扑克牌排名,以及表示其面值的原始Int值。(此原始Int值不用于Jack、Queen、King和Ace卡。)

如上所述,Rank枚举定义了自己的进一步嵌套结构,称为Values。这种结构概括了一个事实,即大多数卡片只有一个值,但Ace卡有两个值。Values结构定义了两个属性来表示这一点:

  • first,类型Int
  • second,类型为Int?,或“optional Int

Rank还定义了一个计算属性,即values,它返回Values结构的实例。此计算属性考虑卡的排名,并根据排名使用适当的值初始化一个新的Values实例。它为jackqueenkingace使用特殊值。对于数字卡,它使用排名的原始Int值。

BlackjackCard结构本身有两个属性——ranksuit。它还定义了一个名为description计算属性,该属性使用ranksuit中存储的值来构建卡片名称和值的描述。description属性使用可选绑定来检查是否有第二个值要显示,如果是,则为第二个值插入额外的描述细节。

由于BlackjackCard是一个没有自定义初始化器的结构,因此它有一个隐式成员初始化器,如结构类型的成员初始化器中所述。您可以使用此初始化器初始化名为theAceOfSpades的新常量:

  1. let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
  2. print(“theAceOfSpades: (theAceOfSpades.description)”)
  3. // Prints “theAceOfSpades: suit is ♠, value is 1 or 11”

即使RankSuit嵌套在BlackjackCard中,它们的类型可以从上下文中推断出来,因此此实例的初始化只能通过它们的大小写名称(.ace.spades)来引用枚举案例。在上面的示例中,description属性正确地报告黑桃王牌的值为1或11。

提及嵌套类型

要在其定义上下文之外使用嵌套类型,请在其名称前加上嵌套在其中的类型名称:

  1. let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
  2. // heartsSymbol is “♡”

对于上面的例子,这使SuitRankValues的名称可以故意保持简短,因为它们的名字自然会被定义它们的上下文所限定。