Skip to content

在另一个类型的范围内定义类型。 列举常用于支持特定类或结构的功能。同样,在更复杂的类型上下文中仅用于定义实用结构也是方便的,通常与特定类型一起使用的协议也是如此。为了实现这一点,Swift 允许定义嵌套类型,在这种情况下,您可以在支持它们的类型定义中嵌套诸如枚举、结构和协议等支持类型。

要在一个类型中嵌套另一个类型,将其定义写在支持它的外部类型的花括号内。类型可以嵌套到所需的任何级别。

嵌套类型的用法

以下示例定义了一个称为 BlackjackCard 的结构,用于模拟纸牌游戏 21 点中的纸牌。 BlackjackCard 结构包含两个嵌套的枚举类型 SuitRank

在 21 点游戏中,A 牌的价值可以是 1 或 11。这一特性由一个称为 Values 的结构表示,该结构嵌套在 Rank 枚举中:

swift
struct BlackjackCard {


    // nested Suit enumeration
    enum Suit: Character {
        case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
    }


    // nested Rank enumeration
    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 properties and methods
    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 和 A 牌。)

如上所述, Rank 枚举定义了其自身的进一步嵌套结构,称为 Values 。该结构封装了大多数牌只有一个价值,但 A 牌有两个价值的事实。 Values 结构定义了两个属性来表示这一点:

  • first ,类型为 Int
  • second ,类型为 Int? ,或者“可选的 Int

Rank 还定义了一个计算属性 values ,它返回一个 Values 结构的实例。此计算属性会考虑牌的等级,并根据其等级初始化一个新的 Values 实例,使用特定值表示 jackqueenkingace 。对于数值牌,它使用牌等级的原始 Int 值。

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

因为 BlackjackCard 没有自定义初始化器,所以它有一个隐式的成员 wise 初始化器,如结构类型成员 wise 初始化器中所述。你可以使用这个初始化器来初始化一个新的常量 theAceOfSpades :

swift
let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
print("theAceOfSpades: \(theAceOfSpades.description)")
// Prints "theAceOfSpades: suit is ♠, value is 1 or 11"

尽管 RankSuit 包含在 BlackjackCard 中,但它们的类型可以从上下文中推断出来,因此该实例的初始化能够仅通过它们的名称( .ace.spades )来引用枚举情况。在上面的例子中, description 属性正确地报告了方块梅花的值为 1 或 11 。

引用嵌套类型

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

swift
let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
// heartsSymbol is "♡"

以上示例中,这使得 SuitRankValues 的名字可以故意保持简短,因为它们的名字在定义时自然地由上下文限定。