Swift語言中,具有類特征的類型包括三種,即枚舉類型、結構類型(包括基本類型,基本類型實際都是結構類型的特例)、類。其中枚舉類型、結構類型是屬于值類型,類屬于引用類型。三種類型都可以添加屬性、方法、下標方法,能夠使用擴展進行功能擴展,使用協議等。
枚舉
枚舉定義了一種包含一組相關值的公共類型。枚舉是Swift中的一種與類類似的類型,具有許多傳統類才有的特征,例如計算屬性、實例方法,能夠通過擴展或協議增強功能等。
- 枚舉定義,Swift 語言的枚舉類型的定義語法如下:
enum CompassPoint {
case North
case South
case East
case West
}
枚舉語法以一個關鍵字enum來標識,enum后面包含一個枚舉類型名字,枚舉定義全部放到一對大括號中。 在枚舉中定義的值稱為枚舉成員值,用case關鍵字來指示一個新的枚舉成員值。 與C和Objective-C語言的枚舉類型不同的是:在Swift中不需要為枚舉成員分配一個默認的整數值。 如果為枚舉成員提供值,該值可以是一個字符串、一個字符或者是一個任意整數或浮點數。枚舉成員值可以定義到一行中,并用逗號分割。
enum Planet {
case Mercury,Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune
}
- 枚舉的使用
可以為一個常量或變量分配一種枚舉類型的值,如:
var directionToHead =CompassPoint.West
以上定義的變量directionToHead可以推斷為是一種CompassPoint類型的枚舉變量,因此你可以設置該變量為CompassPoint類型的其它值,如:
directionToHead = .East //枚舉類型被省略
枚舉也能夠在switch語句中使用,用來匹配獨立的枚舉值:
directionToHead = .South
switch directionToHead {
case .North:
println("Lots of planets have a north")
case .South:
println("Watch out for penguins")
case .East:
println("Where the sun rises")
case .West:
println("Where the skies are blue")
}
- 為枚舉成員分配相關值
Swift中能夠為每一個枚舉成員規定一個任意類型的相關值,并且為每個枚舉成員規定的相關值的類型可以不同。
enum Barcode {
case UPCA(Int,Int,Int)
case QRCode(String)
}
該例子定義了一個類型為Barcode的枚舉類型,并定義了兩個枚舉值UPCA 和QRCode,并可以為枚舉值UPCA 分配一個多元組類型的相關值,為QRCode分配一個字符串類型的相關值,該例子沒有為枚舉值本身指定任何類型的值。
可以使用以上定義的枚舉為一個常量或變量賦值,如:
var productBarcode =Barcode.UPCA(8,85909_51226,3)
還可以在switch語句中使用該枚舉,并通過綁定常量或變量的方式引出其帶有的相關類型的值:
switch productBarcode {
case .UPCA(let numberSystem,let identifier,let check):
println("UPC-A with value of\(numberSystem),\(identifier),\(check).")
case .QRCode(let productCode):
println("QR code with value of\(productCode).")
}
如果枚舉成員的所有的相關值都作為常量被引出,或者所有的相關值都作為變量形式被引出,以上語法還可以簡寫為如下形式:
switch productBarcode {
case let .UPCA(numberSystem,identifier,check):
println("UPC-A with value of\(numberSystem),\(identifier),\(check).")
case let .QRCode(productCode):
println("QR code with value of\(productCode).")
}
- 為枚舉分配原始值
除了為枚舉成員分配相關的值外,還能為每個枚舉成員預分配一個同類型的原始值。這與C 語言為枚舉成員分配一個整數值類似,但Swift定義的原始值的類型可以是字符串、字符、或任意的整數或浮點數類型等,如:
enum ASCIIControlCharacter:Character {
case Tab ="\t"
case LineFeed ="\n"
case CarriageReturn ="\r"
}
該例子中,定義了一個含有三個枚舉成員的枚舉類型ASCIIControlCharacter,并指定其原始類型為字符類型,并為每個枚舉成員分配一個字符類型的默認原始值。
與C語言為枚舉成員指定值類似,Swift要求為枚舉的每個枚舉成員分配的原始值必須在枚舉聲明內唯一。當使用整數類型的原始值時,枚舉成員的其它原始值如果沒有指定,其能夠在第一個枚舉成員定義值的基礎上自動加1,如下所示:
enum Planet:Int {
case Mercury =1,Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune
}
為枚舉成員定義的原始值與為枚舉成員分配的相關值不同,枚舉成員的原始值是在枚舉第一次定義時被分配的,而枚舉成員的相關值雖然其類型也是在枚舉定義時指定,但其值是在使用枚舉類型創建一個常量或變量時設置的。
在Swift中,能夠使用枚舉成員的rawValue方法來獲取枚舉成員的原始值:
let earthsOrder = Planet.Earth.rawValue()
結構與類
- 兩者比較
在Swift中,結構和類功能上幾乎相同,兩者都具有如下相同的功能:- 可以定義屬性,用來存儲值;
- 可以定義方法,用來提供功能;
- 可以定義一個腳本方法,用來使用腳本語法來存取它們的值;
- 能夠定義初始化方法來設置它們的初始狀態;
- 能夠擴展來增加原先沒有實現的功能;
- 能夠遵從相關協議來提供確定類型的標準功能。
類在以下方面與結構存在差別: - 類能夠繼承,一個類能夠繼承它的超類的特性,而結構不能繼承;
- 類允許在運行時檢查和解釋一個類實例的類型;
- 類可以帶有析構函數,允許類的實例釋放它所分配的任何資源;
- 引用計數允許一個類實例有多個引用。
- 結構在代碼中總是以復制方式來傳遞,而不使用引用計數。
- 類和結構的定義和實例化
類和結構的定義采用相似的語法,類使用class關鍵字來指示,結構使用struct關鍵字來指示。
struct Resolution {
var width =0
var height =0
}
class VideoMode {
var resolution =Resolution()
var interlaced =false
var frameRate =0.0
var name:String?
}
每個新定義的類或結構都定義了一種新的類型。
上面例子定義了一種稱作Resolution的新的結構類型,其中包含和定義了兩個變量類型的屬性。還定義了一個稱作VideoMode的新類,該類定義和包含四個變量類型的屬性,其第一個屬性resolution還使用了剛剛定義的結構Resolution的實例進行了初始化。
類和結構中定義的變量或常量類型的屬性像通常變量和常量一樣進行初始化和賦值,屬性的類型可以根據為其提供的初始值進行推斷。
為類和結構創建實例的語法相同:
let someResolution =Resolution()
let someVideoMode =VideoMode()
該例子采用了結構和類初始化最簡單的語法形式(結構和類的類型名面跟著一對圓括號)。該初始化語法為結構和類創建了一個新的各自的實例,并賦值給兩個常量,兩個實例的屬性也在該初始化方法中被初始化為它們的默認值。
在Swift中,所有的結構類型都會自動產生一個參數初始化方法,可以使用該方法來初始化和創建結構的新的實例及其成員屬性,新創建實例的屬性的初始值使用該初始化方法的參數傳進來的值,如:
let vga =Resolution(width:640,height:480)。
而類沒有提供相對應的默認的參數初始化方法。
在Swift中,與腳本語言類似,可以使用點語法的形式來存取一個結構或類實例的屬性以及子屬性,即讀取和設置其值:
讀取屬性的值:
println("The width of someResolution is\(someResolution.width)”)
println("The width of someVideoMode is\(someVideoMode.resolution.width)”)
設置一個屬性的值:
someVideoMode.resolution.width = 1280
- 結構、類與枚舉的類型
在Swift中,結構和枚舉與其它基本類型(整型、浮點類型、布爾類型、字符串、數組和詞典,這些類型其實都是以結構類型實現的)一樣屬于值類型。這意味著它們在分配給一個變量或常量時或當它作為參數傳送給一個函數時,它們的實例以及它們包含的所有作為值類型的屬性一一被拷貝。
在Swift中,為了提供性能,拷貝采用延遲拷貝的機制,即在實際用到時才拷貝。
let hd = Resolution(width:1920, height:1080)
var cinema =hd
在該例子中,由于Resolution是一個結構類型,因此常量hd和變量cinema屬于Resolution結構類型的不同實例,因為在為變量cinema賦值時發生了拷貝行為。
與結構和枚舉不同,類的類型屬于引用類型。引用類型的實例在分配給一個變量或常量時或當它作為參數傳送給一個函數時,沒有拷貝發生。
let tenEighty =VideoMode()
tenEighty.frameRate = 25.0
let alsoTenEighty =tenEighty
alsoTenEighty.frameRate =30.0
由于VideoMode屬于類,因此現在兩個常量tenEighty和alsoTenEighty引用的是相同的VideoMode實例,只是對應相同實例的不同的名字,因此這兩個常量的屬性值frameRate現在都等于30.0。
注意上面的tenEighty和alsoTenEighty被聲明為兩個常量,而不是變量,這是因為tenEighty和alsoTenEighty本身存儲的只是VideoMode的實例的引用值,而不是VideoMode實例本身,因此你通過它們對引用的類實例的屬性的改變,改變是類實例本身的屬性,而不是引用本身。
由于類是引用類型,就如以上例子所示,多個變量或常量可能引用一個類的相同的實例。為了判斷兩個常量或變量是否引用的是一個類的相同實例,Swift提供了兩個引用比較操作符: ‘===’與 ‘!==’。可以使用這兩個操作符來檢查兩個常量或變量是否引用的是相同的實例:
if tenEighty ===alsoTenEighty {
println("tenEighty and alsoTenEighty refer to the same Resolution instance.")
}
在Swift中,一個常量或變量引用一個類的實例,這與C語言中的指針類似,但在Swift 中,引用不是直接指向內存中一個地址,因此不需要使用C語言中類似的指針符號’*’,用來代表一個引用或指針。