第十九章 嵌套类型
枚举通常情况下是用来支持已创建一个特定的类或结构体的功能的,同样地,枚举可以方便的定义工具类或结构体,从而被某个复杂的类型所使用。为了实现这种功能,Swift 允许你定义嵌套类型,可以在支持的类型中定义嵌套的枚举,类和结构体。要在一个类型中嵌套另一个类型,将嵌套类型的定义写在其外部类型的 {}
内,而且可以根据需要定义多级嵌套。
1. Nested Type in Action (实践中的嵌套类型)
下面这个例子定义了一个结构体BlackjackCard
,用来模拟玩扑克牌的游戏,这个BlackjackCard结构体包含了两个嵌套的枚举类型,Suit
和Rank
。描述的是花色和点数。
struct BlackjackCard {
// 结构体中的枚举Suit描述的是四种花色,和一个character类型原始的值来表示花色的图案,从♠,♡,♢到♣,总共四种不同的花色。
enum Suit: Character {
case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
}
// 枚举Rank描述的是十三个点数,用Int类型来表示牌面的点数,从Ace(1)一直到King(K)13个点数。
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, 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
}
}
从上面的案例中可以看出这个枚举Rank
给他自己里面定义来一个嵌套的结构体Value
,而该结构体定义的两个属性first和second,
first
,Int类型second
,Int? 或者可选Int类型
Rank还定义了一个计算型属性value
,这个会返回一个结构体Value
的一个实例。计算型属性考虑到这个扑克牌的点数和构造一个新的Value实例,该实例构造的这个适当的值基于扑克牌Ace(1)一直到King(K)13的点数。
同样的结构体BlackjackCard
不但定义了两个属性rank和suit,还定义了一个计算型属性description
,该计算型属性description属性用rank和suit中的内容来构建对扑克牌名字和数值的描述。该属性使用可选绑定来检查可选类型second
是否有值,若有值,则在原有的描述中增加对second的描述。
let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
print("theAceOfSpades: \(theAceOfSpades.description)")
// 输出:theAceOfSpades: suit is ♠, value is 1 or 11
该结构体BlackjackCard
它是一个没有自定义的构造器,所以该结构体可以使用成员逐一构造器用于构造新的常量值theAceOfSpades
。
即便是这个Rank和Suit嵌套在结构体BlackjackCard,它们的类型可以从上下文中被自动推断出来,以在初始化实例时能够单独通过成员名称( .Ace 和 .Spades )引用枚举实例,在上面的例子中,属性description能够正确的报告出AceOfSpades从1到11的值。
2. Referring to Nested Types (嵌套类型引用)
在定义的上下文外部使用嵌套类型,在嵌套类型的类型名前加上其外部类型的类型名作为前缀: To use a nested type outside of its definition context, prefix its name with the name of the type it is nested within:
// 实例化 并且用dot语法进行一步一步读取某个值
let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
print(heartsSymbol)
// 输出:♡