Swift:枚舉和結(jié)構(gòu)體

Enumerations and Structures

github:Swift基礎(chǔ)實例
github:SwiftBasicTableView

枚舉
  1. 枚舉
    enum 創(chuàng)建一個枚舉,與類和所有其他指定的類型一樣,枚舉可以擁有和它相關(guān)聯(lián)的方法:
enum Rank: Int {
    
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King   
}

讓它包含一個和它關(guān)聯(lián)的方法 simpleDescription()

enum Rank: Int {
    //enum case must declare a raw value when the preceding raw value is not an integer
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King
    func simpleDescription() ->String {
        switch self {
        case .Ace:
            return "ace"
        case .Jack:
            return "jack"
        case .Queen:
            return "queen"
        case .King:
            return "king"
        default:
            return String(self.rawValue)
        }
    }
}
let ace = Rank.Ace
let aceRawValue = ace.rawValue          //1
let aceString = ace.simpleDescription() //"ace"
  • 上面代碼中 case Ace = 11Ace 的原始值,稱為rawValue,類型是 Int,后面的枚舉值依次遞增,如Two就是2,依次類推。
  • 枚舉的類型也可以 StringFloat類型,但是除了 Int類型之外,其他類型的rawValue 都不可以遞增,每一個 enum case 都需要指定一個相應(yīng)類型的值作為它的 rawValue。
  1. 枚舉構(gòu)造器
    帶有rawValueenum會自動接收一個可失敗構(gòu)造器 init?(rawValue:),它根據(jù)枚舉其中一個 raw value,找到合適的case,生成枚舉的實例對象;如果沒有匹配到合適的case,則返回nil
let convertRank = Rank(rawValue: 3)
if  convertRank != nil {
      let threeDescription = convertRank.simpleDescription()
      print(threeDescription) //"3"
}
else {
      print("Have no this enum")
}
  1. 枚舉的值
    在枚舉中 case 后的值就是枚舉實際的值,不僅僅是它們的raw value 的另一種寫法。實際上,也可以不為枚舉提供 raw value
enum Suit {
    case Spades, Hearts, Diamonds, Clubs
    func simpleDescription() ->String {
        switch self {
        case .Spades:
            return "spades"
        case .Hearts:
            return "hearts"
        case .Diamonds:
            return "diamonds"
        case .Clubs:
            return "clubs"
        }
    }
}
let hearts = Suit.Hearts
// 在這個枚舉中,我們沒有提供 `raw value` ,當(dāng)強行調(diào)用 rawValue 時,編譯器會把 `rawValue` 當(dāng)做一個成員變量,因此會報錯:找不到這個成員
// let rawValue = hearts.rawValue; 
let heartsDes = hearts.simpleDescription() //"hearts"

注意上面 Hearts 有兩種被引用方式,第一種是在 switch 中,通過簡寫形式 .Hearts; 第二種是通過 Suit.Hearts,給 hearts賦值。第一種是因為通過 self 已經(jīng)知道是 Suit,所以可以使用簡寫形式.Hearts;第二種由于 hearts 沒有明確給出類型,所以只能寫全名。因此,以下的寫法也是對的:
switch self { case Suit.Hearts:......}
let heartAbb: Suit = .Hearts

  1. 枚舉的關(guān)聯(lián)值(associated values)
    枚舉的 case 值可以存儲一些和它相關(guān)的其他類型的值,稱為關(guān)聯(lián)值(associated values)。
    比如一個商品的條形碼,條形碼由4部分0-9的數(shù)字組成:第一部分是只有1個數(shù)字的數(shù)字位;第二部分是5個數(shù)字的制造位;第三部分是5個數(shù)字的產(chǎn)品位;第四部分是1個數(shù)字的校驗位。一個二維碼卻可以包含所有一維碼的信息,同時還可以包含一些其他信息。我們用枚舉的形式來表現(xiàn)這個二維碼:
enum Barcode {
    case UPCA(Int, Int, Int, Int)
    case QRCode(String)
}

上面代碼可以理解為:一個枚舉名字叫 Barcode,這個枚舉包含一個值 UPCAUPCA有一個類型為(Int, Int, Int, Int) 的關(guān)聯(lián)值,或者包含一個值 QRCode,QRCode 有一個類型為(String)的關(guān)聯(lián)值。生成一個含有關(guān)聯(lián)值的枚舉對象:

var barcode = Barcode.UPCA(9, 72345, 77787, 8)
//barcode 被替換為QRCode(String),barcode 只能存儲其中之一
barcode = .QRCode("abcdef")
switch barcode {
case .UPCA(let numberSystem, let manufacture, let product, let check):
       print("UPC-A: \(numberSystem) \(manufacture) \(product) \(check)")
case .QRCode(let productCode):
       print("QR Code: \(productCode)")
}
//prints "QR Code: abcdef"

如果關(guān)聯(lián)值的類型都是常量(constant)變量(variable),那么只需要在 case 前寫一個 letvar ,就可以了:

switch barcode {
case let .UPCA(numberSystem, manufacture, product, check):
       print("UPC-A: \(numberSystem) \(manufacture) \(product) \(check)")
case let .QRCode(productCode):
       print("QR Code: \(productCode)")
}
//prints "QR Code: abcdef"
結(jié)構(gòu)體
  • 用關(guān)鍵字 struct 創(chuàng)建一個結(jié)構(gòu)體。
    結(jié)構(gòu)體(struct) 和 類(class)有很多相似的地方,也包含有屬性、方法和初始化構(gòu)造器。主要來看一下它們的不同點:
  • class 有繼承,struct 沒有
  • runtime 期間,根據(jù) Type casting (類型轉(zhuǎn)換),可以得知一個實例( instance)所屬于的類
  • class 有析構(gòu)函數(shù),struct 沒有
  • class 可以使用 ARC

最重要的,結(jié)構(gòu)體屬于值類型,在代碼中傳遞的時候,每次都會被復(fù)制(copy)一份,而類是通過引用(reference)傳遞的:

struct Card {
    var score : Int
}

let cart      = Cart(score: 3)
var varCart   = cart
varCart.score = 5
print(cart.score) // 3
print(varCart.score) // 5

可以看到,我們把對象 cart 賦值給 varCart 后,修改 varCart 的屬性值,并不會對 cart 的屬性值造成影響。這和下面的 class 完全不同:

class testInit {
    
    var number = 0
    var point = 9
}

let testI    = testInit()
let testII   = testI
testII.point = 8
print(testI.point) // 8

當(dāng)我們把對象 testI 賦值給 testII 后,修改 testII 的屬性 point,由于類是引用類型(相應(yīng)說明參考概念解釋),

通過下面的代碼,我們來認(rèn)識 struct 中很重要的一個概念:成員構(gòu)造器。(該構(gòu)造器的說明請參考 概念解釋)

struct Card {
    var rank : Rank
    var suit : Suit    

    func simpleDescription()-> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeDes = threeOfSpades.simpleDescription() //"The 3 of spades"

上面的代碼中,我們使用了函數(shù) Card(_: , _: ) 生成一個對象,此函數(shù)是 struct 自動接收的,稱為 成員構(gòu)造器 (Memberwise initializer)

需要注意到是,上面結(jié)構(gòu)體內(nèi)的兩個屬性 ranksuit 在聲明時并沒有初始化,而是在生成 threeOfSpades 實例對象的時候才初始化,因此,結(jié)構(gòu)體只接收一個成員構(gòu)造器。如果這兩個屬性在聲明的時候已經(jīng)初始化,那么,結(jié)構(gòu)體將接收兩個構(gòu)造器:Card()Card(_: , _: ) 。少初始化任何一個屬性,都只會接收一個構(gòu)造器:Card(_: , _: )

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容