型別嵌套

优质
小牛编辑
133浏览
2023-12-01

列舉型別常被用於實作特定類別或結構的功能。也能夠在有多種變數型別的環境中,方便地定義通用類別或結構來使用,為了實作這種功能,Swift允許你定義型別嵌套,可以在列舉型別、類別和結構中定義支援嵌套的型別。

要在一個型別中嵌套另一個型別,將需要嵌套的型別的定義寫在被嵌套型別的區域{}內,而且可以根據需要定義多級嵌套。

型別嵌套實例

下面這個範例定義了一個結構BlackjackCard(二十一點),用來模擬BlackjackCard中的撲克牌點數。BlackjackCard結構包含2個嵌套定義的列舉型別SuitRank

BlackjackCard規則中,Ace牌可以表示1或者11,Ace牌的這一特征用一個嵌套在列舉型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.toRaw(), second: nil)
            }
       }
    }

    // BlackjackCard 的屬性和方法
    let rank: Rank, suit: Suit
    var description: String {
    var output = "suit is \(suit.toRaw()),"
        output += " value is \(rank.values.first)"
        if let second = rank.values.second {
            output += " or \(second)"
        }
        return output
    }
}

列舉型的Suit用來描述撲克牌的四種花色,並分別用一個Character型別的值代表花色符號。

列舉型的Rank用來描述撲克牌從Ace~10,J,Q,K,13張牌,並分別用一個Int型別的值表示牌的面值。(這個Int型別的值不適用於Ace,J,Q,K的牌)。

如上文所提到的,列舉型Rank在自己內部定義了一個嵌套結構Values。這個結構包含兩個變數,只有Ace有兩個數值,其余牌都只有一個數值。結構Values中定義的兩個屬性:

first, 為Int second, 為 Int?, 或 「optional Int

Rank定義了一個計算屬性values,這個計算屬性會根據牌的面值,用適當的數值去初始化Values實例,並賦值給values。對於J,Q,K,Ace會使用特殊數值,對於數字面值的牌使用Int型別的值。

BlackjackCard結構自身有兩個屬性—ranksuit,也同樣定義了一個計算屬性descriptiondescription屬性用ranksuit的中內容來構建對這張撲克牌名字和數值的描述,並用可選型別second來檢查是否存在第二個值,若存在,則在原有的描述中增加對第二數值的描述。

因為BlackjackCard是一個沒有自定義建構函式的結構,在Memberwise Initializers for Structure Types中知道結構有預設的成員建構函式,所以你可以用預設的initializer去初始化新的常數theAceOfSpades:

let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
println("theAceOfSpades: \(theAceOfSpades.description)")
// 列印出 "theAceOfSpades: suit is ♠, value is 1 or 11"

儘管RankSuit嵌套在BlackjackCard中,但仍可被參考,所以在初始化實例時能夠通過列舉型別中的成員名稱單獨參考。在上面的範例中description屬性能正確得輸出對Ace牌有1和11兩個值。

型別嵌套的參考

在外部對嵌套型別的參考,以被嵌套型別的名字為前綴,加上所要參考的屬性名:

let heartsSymbol = BlackjackCard.Suit.Hearts.toRaw()
// 紅心的符號 為 "♡"

對於上面這個範例,這樣可以使Suit, Rank, 和 Values的名字盡可能的短,因為它們的名字會自然的由被定義的上下文來限定。

preview