Gather ye rosebuds while ye may

「翻译」 Swift 内嵌类型


这是对 swift 2.2 中 内嵌类型 一节的翻译
第二篇了,这篇少。

内嵌类型

枚举通常用于实现特定类或结构体的功能。类似的,它也可以在更加复杂的类型环境中方便的定义通用类和结构体。为实现这种功能,Swift 允许你定义内嵌类型,借此在支持类型的定义中嵌套枚举、类、或结构体。

若要在一种类型中嵌套另一种类型,在其支持类型的大括号内定义即可。可以根据需求多级嵌套数个类型。

内嵌类型的实例

下方的例子定义了一个名为BlackJackCard的结构体,模拟了 Blackjack 游戏中的扑克牌。BlackjackCard结构体包含两个嵌套的枚举类型SuitRank

在 Blackjack 游戏中,Ace 可以表示1或11两个值,这通过Rank枚举中嵌套的结构体Values决定:

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
31
32
33
34
35
36
37
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并不会用于 J、Q、K、Ace 的表示)。

如上所述,Rank枚举中定义了一个嵌套结构体Values。这个结构体描述了大多牌只有一个值,而 Ace 可以有两个值这一事实。Values结构体定义了两个属性:

  • Int类型的first
  • Int?类型的second,也称为『可选Int

Rank 还定义了一个计算属性values,用于返回Values结构体的实例。这个计算属性会根据牌的点数,用适当的值初始化新的Values实例。对于JackQueenKing、和Ace使用特殊的值。而对于数值的牌,则使用它本身的Int值。

BlackjackCard结构体本身有两个属性——ranksuit。并定义了一个名为description的计算属性,用ranksuit储存的值构建对扑克牌花色和值的描述。description属性使用可选绑定来检查是否有第二个值要描述,若有,则添加对第二个值的描述。

由于BlackjackCard是一个没有自定义初始化器的结构体,如逐个成员初始化器的结构类型所述,它有一个隐式的成员初始化器。你可以使用这个舒适化其去初始化新的常量theAceOfSpades

1
2
3
let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
print("theAceOfSpades: \(theAceOfSpades.description)")
// 输出 "theAceOfSpades: suit is ♠, value is 1 or 11"

尽管RankSuit被嵌套在BlackjackCard中,但其类型仍可从上下文中推断出来,因此,该实例的初始化器可以单独通过成员名称(.Ace.Spades)引用枚举类型。在上面的例子中,description属性正确的反馈了黑桃 Ace 拥有1或11两个值。

引用内嵌类型

要在定义外部使用内嵌类型,只需在其前缀加上内嵌了它的类的类型名即可:

1
2
let heartsSymbol = BlackjackCard.Suit.Hearts.rawValue
// heartsSymbol 值为 "♡”

像上面的例子可以使SuitRankValues的名字尽可能的短,因为他们的名字由定义时的上下文自然限定。