嵌套类型
在另一个类型的作用域内定义类型。
枚举常被创建以支持特定类或结构的功能。同样的,为了在更复杂类型的上下文中使用而定义纯工具性结构,以及通常与特定类型结合使用的协议,也显得十分便利。为了实现这一点,Swift 允许你定义 嵌套类型,即在支持的类型定义中嵌套枚举、结构和协议等辅助类型。
要在一个类型中嵌套另一个类型,只需将其定义写在外部类型的大括号内。类型可以根据需要嵌套到任意层次。
使用嵌套类型
下面的示例定义了一个名为BlackjackCard 的结构,用于模拟 Blackjack 游戏中的扑克牌。BlackjackCard结构包含两个嵌套的枚举类型,分别是 Suit 和Rank。
在 Blackjack 中,Ace 牌的值可以是 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 值。
Rank 枚举描述了十三种可能的扑克牌等级,以及用于表示其数值的原始 Int 值
(这个原始的 Int 值不适用于杰克 (Jack)、皇后 (Queen)、国王 (King) 和王牌 (Ace) 牌。)
正如上面提到的,Rank 枚举定义了一个它自己的进一步嵌套的结构,叫做 Values。
这个结构封装了大多数牌只有一个值,而王牌 (Ace) 有两个值的事实。
Values 结构定义了两个属性来表示这一点:
Rank还定义了一个计算属性values,它返回一个 Values结构的实例。 该计算属性会根据牌的等级 (rank) 生成一个新的Values实例,并为不同的等级分配合适的值。 对于jack、queen、king和ace,使用特殊的值。 对于数字牌,则使用等级的原始 Int 值。
BlackjackCard 结构本身有两个属性 —— rank 和 suit。它还定义了一个名为 description 的计算属性,该属性使用 rank 和 suit 中存储的值来构建牌的名称和数值的描述。description 属性使用可选绑定来检查是否存在第二个值,如果有,则为第二个值插入额外的描述信息。
由于 BlackjackCard 是一个没有自定义初始化器的结构体,它具有一个隐式的成员逐一初始化器,正如在 [doc:Initialization#Memberwise-Initializers-for-Structure-Types]中所描述的那样。你可以使用这个初始化器来初始化一个名为 theAceOfSpades 的新常量:
let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
print("theAceOfSpades: \(theAceOfSpades.description)")
// 输出 "theAceOfSpades: suit is ♠, value 是 1 或者 11"
尽管 Rank 和 Suit 嵌套在 BlackjackCard 中,它们的类型可以从上下文中推断出来,因此在初始化这个实例时,可以仅通过它们的名称(如 .ace 和 .spades)来引用枚举的情况。
在上面的示例中,description 属性正确地记录了黑桃 A 的值为 1 或 11。
访问嵌套类型
要在定义上下文之外使用嵌套类型,需要在其名称前加上其外部类型的名称前缀:
let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
// heartsSymbol 是 "♡"
在上面的例子中,这使得 Suit, Rank, 和 Values的名称可以故意保持简短,因为它们的名称由定义它们的上下文自然限定。