1.0 翻譯:lyuka 校對(duì):numbbbbb, stanzhai
2.0 翻譯+校對(duì):EudeMorgen
2.1 翻譯:mmoaay
4.1 翻譯+校對(duì):mylittleswift
本頁(yè)包含內(nèi)容:
Swift 語(yǔ)言存在兩種類(lèi)型:命名型類(lèi)型和復(fù)合型類(lèi)型。命名型類(lèi)型是指定義時(shí)可以給定名字的類(lèi)型。命名型類(lèi)型包括類(lèi)、結(jié)構(gòu)體、枚舉和協(xié)議。比如,一個(gè)用戶(hù)定義的類(lèi) MyClass 的實(shí)例擁有類(lèi)型 MyClass。除了用戶(hù)定義的命名型類(lèi)型,Swift 標(biāo)準(zhǔn)庫(kù)也定義了很多常用的命名型類(lèi)型,包括那些表示數(shù)組、字典和可選值的類(lèi)型。
那些通常被其它語(yǔ)言認(rèn)為是基本或原始的數(shù)據(jù)型類(lèi)型,比如表示數(shù)字、字符和字符串的類(lèi)型,實(shí)際上就是命名型類(lèi)型,這些類(lèi)型在 Swift 標(biāo)準(zhǔn)庫(kù)中是使用結(jié)構(gòu)體來(lái)定義和實(shí)現(xiàn)的。因?yàn)樗鼈兪敲皖?lèi)型,因此你可以按照 擴(kuò)展 和 擴(kuò)展聲明 中討論的那樣,聲明一個(gè)擴(kuò)展來(lái)增加它們的行為以滿(mǎn)足你程序的需求。
復(fù)合型類(lèi)型是沒(méi)有名字的類(lèi)型,它由 Swift 本身定義。Swift 存在兩種復(fù)合型類(lèi)型:函數(shù)類(lèi)型和元組類(lèi)型。一個(gè)復(fù)合型類(lèi)型可以包含命名型類(lèi)型和其它復(fù)合型類(lèi)型。例如,元組類(lèi)型 (Int, (Int, Int)) 包含兩個(gè)元素:第一個(gè)是命名型類(lèi)型 Int,第二個(gè)是另一個(gè)復(fù)合型類(lèi)型 (Int, Int)。
你可以在命名型類(lèi)型和復(fù)合型類(lèi)型使用小括號(hào)。但是在類(lèi)型旁加小括號(hào)沒(méi)有任何作用。舉個(gè)例子,(Int) 等同于 Int。
本節(jié)討論 Swift 語(yǔ)言本身定義的類(lèi)型,并描述 Swift 中的類(lèi)型推斷行為。
類(lèi)型語(yǔ)法
類(lèi)型 → 數(shù)組類(lèi)型 類(lèi)型 → 字典類(lèi)型 類(lèi)型 → 函數(shù)類(lèi)型 類(lèi)型 → 類(lèi)型標(biāo)識(shí) 類(lèi)型 → 元組類(lèi)型 類(lèi)型 → 可選類(lèi)型 類(lèi)型 → 隱式解析可選類(lèi)型 類(lèi)型 → 協(xié)議合成類(lèi)型 類(lèi)型 → 元型類(lèi)型 類(lèi)型 → 任意類(lèi)型 類(lèi)型 → 自身類(lèi)型 類(lèi)型 → (類(lèi)型)
類(lèi)型注解顯式地指定一個(gè)變量或表達(dá)式的值。類(lèi)型注解始于冒號(hào) : 終于類(lèi)型,比如下面兩個(gè)例子:
let someTuple: (Double, Double) = (3.14159, 2.71828)
func someFunction(a: Int) { /* ... */ }
在第一個(gè)例子中,表達(dá)式 someTuple 的類(lèi)型被指定為 (Double, Double)。在第二個(gè)例子中,函數(shù) someFunction 的參數(shù) a 的類(lèi)型被指定為 Int。
類(lèi)型注解可以在類(lèi)型之前包含一個(gè)類(lèi)型特性的可選列表。
類(lèi)型注解語(yǔ)法
類(lèi)型標(biāo)識(shí)符引用命名型類(lèi)型,還可引用命名型或復(fù)合型類(lèi)型的別名。
大多數(shù)情況下,類(lèi)型標(biāo)識(shí)符引用的是與之同名的命名型類(lèi)型。例如類(lèi)型標(biāo)識(shí)符 Int 引用命名型類(lèi)型 Int,同樣,類(lèi)型標(biāo)識(shí)符 Dictionary<String, Int> 引用命名型類(lèi)型 Dictionary<String, Int>。
在兩種情況下類(lèi)型標(biāo)識(shí)符不引用同名的類(lèi)型。情況一,類(lèi)型標(biāo)識(shí)符引用的是命名型或復(fù)合型類(lèi)型的類(lèi)型別名。比如,在下面的例子中,類(lèi)型標(biāo)識(shí)符使用 Point 來(lái)引用元組 (Int, Int):
typealias Point = (Int, Int)
let origin: Point = (0, 0)
情況二,類(lèi)型標(biāo)識(shí)符使用點(diǎn)語(yǔ)法(.)來(lái)表示在其它模塊或其它類(lèi)型嵌套內(nèi)聲明的命名型類(lèi)型。例如,下面例子中的類(lèi)型標(biāo)識(shí)符引用在 ExampleModule 模塊中聲明的命名型類(lèi)型 MyType:
var someValue: ExampleModule.MyType
類(lèi)型標(biāo)識(shí)符語(yǔ)法
類(lèi)型標(biāo)識(shí)符 → 類(lèi)型名稱(chēng) 泛型參數(shù)子句可選 | 類(lèi)型名稱(chēng) 泛型參數(shù)子句可選 . 類(lèi)型標(biāo)識(shí)符 類(lèi)型名稱(chēng) → 標(biāo)識(shí)符
元組類(lèi)型是使用括號(hào)括起來(lái)的零個(gè)或多個(gè)類(lèi)型,類(lèi)型間用逗號(hào)隔開(kāi)。
你可以使用元組類(lèi)型作為一個(gè)函數(shù)的返回類(lèi)型,這樣就可以使函數(shù)返回多個(gè)值。你也可以命名元組類(lèi)型中的元素,然后用這些名字來(lái)引用每個(gè)元素的值。元素的名字由一個(gè)標(biāo)識(shí)符緊跟一個(gè)冒號(hào) (:) 組成。函數(shù)和多返回值 章節(jié)里有一個(gè)展示上述特性的例子。
當(dāng)一個(gè)元組類(lèi)型的元素有名字的時(shí)候,這個(gè)名字就是類(lèi)型的一部分。
var someTuple = (top: 10, bottom: 12) // someTuple 的類(lèi)型為 (top: Int, bottom: Int)
someTuple = (top: 4, bottom: 42) // 正確:命名類(lèi)型匹配
someTuple = (9, 99) // 正確:命名類(lèi)型被自動(dòng)推斷
someTuple = (left: 5, right: 5) // 錯(cuò)誤:命名類(lèi)型不匹配
所有的元組類(lèi)型都包含兩個(gè)及以上元素, 除了 Void。Void 是空元組類(lèi)型 () 的別名。
元組類(lèi)型語(yǔ)法
元組類(lèi)型 → ( 元組類(lèi)型元素列表 可選 ) 元組類(lèi)型元素列表 → 元組類(lèi)型元素 | 元組類(lèi)型元素 , 元組類(lèi)型元素列表 元組類(lèi)型元素 → 元素名 類(lèi)型注解 | 類(lèi)型 元素名 → 標(biāo)識(shí)符
函數(shù)類(lèi)型表示一個(gè)函數(shù)、方法或閉包的類(lèi)型,它由參數(shù)類(lèi)型和返回值類(lèi)型組成,中間用箭頭(->)隔開(kāi):
參數(shù)類(lèi)型->返回值類(lèi)型
參數(shù)類(lèi)型是由逗號(hào)間隔的類(lèi)型列表。由于參數(shù)類(lèi)型和返回值類(lèi)型可以是元組類(lèi)型,所以函數(shù)類(lèi)型支持多參數(shù)與多返回值的函數(shù)與方法。
你可以對(duì)函數(shù)參數(shù) () -> T(其中 T 是任何類(lèi)型)使用 autoclosure 特性。這會(huì)自動(dòng)將參數(shù)表達(dá)式轉(zhuǎn)化為閉包,表達(dá)式的結(jié)果即閉包返回值。這從語(yǔ)法結(jié)構(gòu)上提供了一種便捷:延遲對(duì)表達(dá)式的求值,直到其值在函數(shù)體中被調(diào)用。以自動(dòng)閉包做為參數(shù)的函數(shù)類(lèi)型的例子詳見(jiàn) 自動(dòng)閉包 。
函數(shù)類(lèi)型可以擁有一個(gè)可變長(zhǎng)參數(shù)作為參數(shù)類(lèi)型中的最后一個(gè)參數(shù)。從語(yǔ)法角度上講,可變長(zhǎng)參數(shù)由一個(gè)基礎(chǔ)類(lèi)型名字緊隨三個(gè)點(diǎn)(...)組成,如 Int...??勺冮L(zhǎng)參數(shù)被認(rèn)為是一個(gè)包含了基礎(chǔ)類(lèi)型元素的數(shù)組。即 Int... 就是 [Int]。關(guān)于使用可變長(zhǎng)參數(shù)的例子,請(qǐng)參閱 可變參數(shù)。
為了指定一個(gè) in-out 參數(shù),可以在參數(shù)類(lèi)型前加 inout 前綴。但是你不可以對(duì)可變長(zhǎng)參數(shù)或返回值類(lèi)型使用 inout。關(guān)于這種參數(shù)的詳細(xì)講解請(qǐng)參閱 輸入輸出參數(shù)。
如果一個(gè)函數(shù)類(lèi)型只有一個(gè)形式參數(shù)而且形式參數(shù)的類(lèi)型是元組類(lèi)型,那么元組類(lèi)型在寫(xiě)函數(shù)類(lèi)型的時(shí)候必須用圓括號(hào)括起來(lái)。比如說(shuō),((Int, Int)) -> Void 是接收一個(gè)元組 (Int, Int) 作為形式參數(shù)的函數(shù)的類(lèi)型。與此相反,不加括號(hào)的 (Int, Int) -> Void 是一個(gè)接收兩個(gè) Int 形式參數(shù)并且不返回任何值的函數(shù)的類(lèi)型。相似地,因?yàn)?Void 是空元組類(lèi)型 () 的別名, 函數(shù)類(lèi)型 (Void)-> Void 與一個(gè)空元組的變量的函數(shù)類(lèi)型 (()) -> () 是一樣的。但這些類(lèi)型和無(wú)變量的函數(shù)類(lèi)型 () -> () 是不一樣的。
函數(shù)和方法中的變量名并不是函數(shù)類(lèi)型的一部分。例如:
func someFunction(left: Int, right: Int) {}
func anotherFunction(left: Int, right: Int) {}
func functionWithDifferentLabels(top: Int, bottom: Int) {}
var f = someFunction // 函數(shù) f 的類(lèi)型為 (Int, Int) -> Void, 而不是 (left: Int, right: Int) -> Void.
f = anotherFunction // 正確
f = functionWithDifferentLabels // 正確
func functionWithDifferentArgumentTypes(left: Int, right: String) {}
func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {}
f = functionWithDifferentArgumentTypes // 錯(cuò)誤
f = functionWithDifferentNumberOfArguments // 錯(cuò)誤
由于變量標(biāo)簽不是函數(shù)類(lèi)型的一部分,你可以在寫(xiě)函數(shù)類(lèi)型的時(shí)候省略它們。
var operation: (lhs: Int, rhs: Int) -> Int // 錯(cuò)誤
var operation: (_ lhs: Int, _ rhs: Int) -> Int // 正確
var operation: (Int, Int) -> Int // 正確
如果一個(gè)函數(shù)類(lèi)型包涵多個(gè)箭頭(->),那么函數(shù)類(lèi)型將從右向左進(jìn)行組合。例如,函數(shù)類(lèi)型 Int -> Int -> Int 可以理解為 Int -> (Int -> Int),也就是說(shuō),該函數(shù)類(lèi)型的參數(shù)為 Int 類(lèi)型,其返回類(lèi)型是一個(gè)參數(shù)類(lèi)型為 Int,返回類(lèi)型為 Int 的函數(shù)類(lèi)型。
函數(shù)類(lèi)型若要拋出錯(cuò)誤就必須使用 throws 關(guān)鍵字來(lái)標(biāo)記,若要重拋錯(cuò)誤則必須使用 rethrows 關(guān)鍵字來(lái)標(biāo)記。throws 關(guān)鍵字是函數(shù)類(lèi)型的一部分,非拋出函數(shù)是拋出函數(shù)函數(shù)的一個(gè)子類(lèi)型。因此,在使用拋出函數(shù)的地方也可以使用不拋出函數(shù)。拋出和重拋函數(shù)的相關(guān)描述見(jiàn)章節(jié) 拋出函數(shù)與方法 和 重拋函數(shù)與方法。
非逃逸閉包函數(shù)不能作為參數(shù)傳遞到另一個(gè)非逃逸閉包函數(shù)的參數(shù)。這樣的限制可以讓 Swift 在編譯時(shí)就完成更多的內(nèi)存訪問(wèn)沖突檢查, 而不是在運(yùn)行時(shí)。舉個(gè)例子:
let external: (Any) -> Void = { _ in () }
func takesTwoFunctions(first: (Any) -> Void, second: (Any) -> Void) {
first(first) // 錯(cuò)誤
second(second) // 錯(cuò)誤
first(second) // 錯(cuò)誤
second(first) // 錯(cuò)誤
first(external) // 正確
external(first) // 正確
}
在上面代碼里,takesTwoFunctions(first:second:) 的兩個(gè)參數(shù)都是函數(shù)。 它們都沒(méi)有標(biāo)記為 @escaping, 因此它們都是非逃逸的。
上述例子里的被標(biāo)記為“錯(cuò)誤”的四個(gè)函數(shù)調(diào)用會(huì)產(chǎn)生編譯錯(cuò)誤。因?yàn)榈谝粋€(gè)和第二個(gè)參數(shù)是非逃逸函數(shù),它們不能夠被當(dāng)作變量被傳遞到另一個(gè)非閉包函數(shù)參數(shù)。與此相反, 標(biāo)記“正確”的兩個(gè)函數(shù)不回產(chǎn)生編譯錯(cuò)誤。這些函數(shù)調(diào)用不會(huì)違反限制, 因?yàn)?外部(external) 不是 takesTwoFunctions(first:second:) 里的一個(gè)參數(shù)。
如果你需要避免這個(gè)限制, 標(biāo)記其中之一的參數(shù)為逃逸, 或者使用 withoutActuallyEscaping(_:do:) 函數(shù)臨時(shí)地轉(zhuǎn)換非逃逸函數(shù)的其中一個(gè)參數(shù)為逃逸函數(shù)。關(guān)于避免內(nèi)存訪問(wèn)沖突,可以參閱內(nèi)存安全。
函數(shù)類(lèi)型語(yǔ)法
函數(shù)類(lèi)型 → 特性列表可選 函數(shù)類(lèi)型子句 throws可選 -> 類(lèi)型 函數(shù)類(lèi)型 → 特性列表可選 函數(shù)類(lèi)型子句 rethrows- -> 類(lèi)型 函數(shù)類(lèi)型子句 → (-)- 函數(shù)類(lèi)型子句 → (函數(shù)類(lèi)型參數(shù)列表...-可選)- 函數(shù)類(lèi)型參數(shù)列表 → 函數(shù)類(lèi)型參數(shù) | 函數(shù)類(lèi)型參數(shù), 函數(shù)類(lèi)型參數(shù)列表 函數(shù)類(lèi)型參數(shù) → 特性列表可選 輸入輸出參數(shù)可選 類(lèi)型 | 參數(shù)標(biāo)簽 類(lèi)型注解 參數(shù)標(biāo)簽 → 標(biāo)識(shí)符
Swift 語(yǔ)言為標(biāo)準(zhǔn)庫(kù)中定義的 Array<Element> 類(lèi)型提供了如下語(yǔ)法糖:
[
類(lèi)型]
換句話(huà)說(shuō),下面兩個(gè)聲明是等價(jià)的:
let someArray: Array<String> = ["Alex", "Brian", "Dave"]
let someArray: [String] = ["Alex", "Brian", "Dave"]
上面兩種情況下,常量 someArray 都被聲明為字符串?dāng)?shù)組。數(shù)組的元素也可以通過(guò)下標(biāo)訪問(wèn):someArray[0] 是指第 0 個(gè)元素 "Alex"。
你也可以嵌套多對(duì)方括號(hào)來(lái)創(chuàng)建多維數(shù)組,最里面的方括號(hào)中指明數(shù)組元素的基本類(lèi)型。比如,下面例子中使用三對(duì)方括號(hào)創(chuàng)建三維整數(shù)數(shù)組:
var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
訪問(wèn)一個(gè)多維數(shù)組的元素時(shí),最左邊的下標(biāo)指向最外層數(shù)組的相應(yīng)位置元素。接下來(lái)往右的下標(biāo)指向第一層嵌入的相應(yīng)位置元素,依次類(lèi)推。這就意味著,在上面的例子中,array3D[0] 是 [[1, 2], [3, 4]],array3D[0][1] 是 [3, 4],array3D[0][1][1] 則是 4。
關(guān)于 Swift 標(biāo)準(zhǔn)庫(kù)中 Array 類(lèi)型的詳細(xì)討論,請(qǐng)參閱 數(shù)組。
數(shù)組類(lèi)型語(yǔ)法
數(shù)組類(lèi)型 → [ 類(lèi)型 ]
Swift 語(yǔ)言為標(biāo)準(zhǔn)庫(kù)中定義的 Dictionary<Key, Value> 類(lèi)型提供了如下語(yǔ)法糖:
[
鍵類(lèi)型:值類(lèi)型]
換句話(huà)說(shuō),下面兩個(gè)聲明是等價(jià)的:
let someDictionary: [String: Int] = ["Alex": 31, "Paul": 39]
let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]
上面兩種情況,常量 someDictionary 被聲明為一個(gè)字典,其中鍵為 String 類(lèi)型,值為 Int 類(lèi)型。
字典中的值可以通過(guò)下標(biāo)來(lái)訪問(wèn),這個(gè)下標(biāo)在方括號(hào)中指明了具體的鍵:someDictionary["Alex"] 返回鍵 Alex 對(duì)應(yīng)的值。如果鍵在字典中不存在的話(huà),則這個(gè)下標(biāo)返回 nil。
字典中鍵的類(lèi)型必須符合 Swift 標(biāo)準(zhǔn)庫(kù)中的 Hashable 協(xié)議。
關(guān)于 Swift 標(biāo)準(zhǔn)庫(kù)中 Dictionary 類(lèi)型的詳細(xì)討論,請(qǐng)參閱 字典。
字典類(lèi)型語(yǔ)法
Swift 定義后綴 ? 來(lái)作為標(biāo)準(zhǔn)庫(kù)中的定義的命名型類(lèi)型 Optional<Wrapped> 的語(yǔ)法糖。換句話(huà)說(shuō),下面兩個(gè)聲明是等價(jià)的:
var optionalInteger: Int?
var optionalInteger: Optional<Int>
在上述兩種情況下,變量 optionalInteger 都被聲明為可選整型類(lèi)型。注意在類(lèi)型和 ? 之間沒(méi)有空格。
類(lèi)型 Optional<Wrapped> 是一個(gè)枚舉,有兩個(gè)成員,none 和 some(Wrapped),用來(lái)表示可能有也可能沒(méi)有的值。任意類(lèi)型都可以被顯式地聲明(或隱式地轉(zhuǎn)換)為可選類(lèi)型。如果你在聲明或定義可選變量或?qū)傩缘臅r(shí)候沒(méi)有提供初始值,它的值則會(huì)自動(dòng)賦為默認(rèn)值 nil。
如果一個(gè)可選類(lèi)型的實(shí)例包含一個(gè)值,那么你就可以使用后綴運(yùn)算符 ! 來(lái)獲取該值,正如下面描述的:
optionalInteger = 42
optionalInteger! // 42
使用 ! 運(yùn)算符解包值為 nil 的可選值會(huì)導(dǎo)致運(yùn)行錯(cuò)誤。
你也可以使用可選鏈?zhǔn)秸{(diào)用和可選綁定來(lái)選擇性地在可選表達(dá)式上執(zhí)行操作。如果值為 nil,不會(huì)執(zhí)行任何操作,因此也就沒(méi)有運(yùn)行錯(cuò)誤產(chǎn)生。
更多細(xì)節(jié)以及更多如何使用可選類(lèi)型的例子,請(qǐng)參閱 可選類(lèi)型。
可選類(lèi)型語(yǔ)法
可選類(lèi)型 → 類(lèi)型 ?
當(dāng)可以被訪問(wèn)時(shí),Swift 語(yǔ)言定義后綴 ! 作為標(biāo)準(zhǔn)庫(kù)中命名類(lèi)型 Optional<Wrapped> 的語(yǔ)法糖,來(lái)實(shí)現(xiàn)自動(dòng)解包的功能。換句話(huà)說(shuō),下面兩個(gè)聲明等價(jià):
var implicitlyUnwrappedString: String!
var explicitlyUnwrappedString: Optional<String>
注意類(lèi)型與 ! 之間沒(méi)有空格。
由于隱式解包修改了包涵其類(lèi)型的聲明語(yǔ)義,嵌套在元組類(lèi)型或泛型的可選類(lèi)型(比如字典元素類(lèi)型或數(shù)組元素類(lèi)型),不能被標(biāo)記為隱式解包。例如:
let tupleOfImplicitlyUnwrappedElements: (Int!, Int!) // 錯(cuò)誤
let implicitlyUnwrappedTuple: (Int, Int)! // 正確
let arrayOfImplicitlyUnwrappedElements: [Int!] // 錯(cuò)誤
let implicitlyUnwrappedArray: [Int]! // 正確
由于隱式解析可選類(lèi)型和可選類(lèi)型有同樣的表達(dá)式 Optional<Wrapped>,你可以在使用可選類(lèi)型的地方使用隱式解析可選類(lèi)型。比如,你可以將隱式解析可選類(lèi)型的值賦給變量、常量和可選屬性,反之亦然。
正如可選類(lèi)型一樣,你在聲明隱式解析可選類(lèi)型的變量或?qū)傩缘臅r(shí)候也不用指定初始值,因?yàn)樗心J(rèn)值 nil。
可以使用可選鏈?zhǔn)秸{(diào)用來(lái)在隱式解析可選表達(dá)式上選擇性地執(zhí)行操作。如果值為 nil,就不會(huì)執(zhí)行任何操作,因此也不會(huì)產(chǎn)生運(yùn)行錯(cuò)誤。
關(guān)于隱式解析可選類(lèi)型的更多細(xì)節(jié),請(qǐng)參閱 隱式解析可選類(lèi)型。
隱式解析可選類(lèi)型語(yǔ)法
隱式解析可選類(lèi)型 → 類(lèi)型 !
協(xié)議合成類(lèi)型是一種符合協(xié)議列表中每個(gè)指定協(xié)議的類(lèi)型。協(xié)議合成類(lèi)型可能會(huì)用在類(lèi)型注解和泛型參數(shù)中。
協(xié)議合成類(lèi)型的形式如下:
Protocol 1&Procotol 2
協(xié)議合成類(lèi)型允許你指定一個(gè)值,其類(lèi)型符合多個(gè)協(xié)議的要求且不需要定義一個(gè)新的命名型協(xié)議來(lái)繼承它想要符合的各個(gè)協(xié)議。比如,協(xié)議合成類(lèi)型 Protocol A & Protocol B & Protocol C 等效于一個(gè)從 Protocol A,Protocol B,Protocol C 繼承而來(lái)的新協(xié)議 Protocol D,很顯然這樣做有效率的多,甚至不需引入一個(gè)新名字。
協(xié)議合成列表中的每項(xiàng)必須是協(xié)議名或協(xié)議合成類(lèi)型的類(lèi)型別名。
協(xié)議合成類(lèi)型語(yǔ)法
協(xié)議合成類(lèi)型 → 協(xié)議標(biāo)識(shí)符 & 協(xié)議合成延續(xù) 協(xié)議合成延續(xù) → 協(xié)議標(biāo)識(shí)符 | 協(xié)議合成類(lèi)型 協(xié)議標(biāo)識(shí)符 → 類(lèi)型標(biāo)識(shí)符
元類(lèi)型是指類(lèi)型的類(lèi)型,包括類(lèi)類(lèi)型、結(jié)構(gòu)體類(lèi)型、枚舉類(lèi)型和協(xié)議類(lèi)型。
類(lèi)、結(jié)構(gòu)體或枚舉類(lèi)型的元類(lèi)型是相應(yīng)的類(lèi)型名緊跟 .Type。協(xié)議類(lèi)型的元類(lèi)型——并不是運(yùn)行時(shí)符合該協(xié)議的具體類(lèi)型——而是該協(xié)議名字緊跟 .Protocol。比如,類(lèi) SomeClass 的元類(lèi)型就是 SomeClass.Type,協(xié)議 SomeProtocol 的元類(lèi)型就是 SomeProtocal.Protocol。
你可以使用后綴 self 表達(dá)式來(lái)獲取類(lèi)型。比如,SomeClass.self 返回 SomeClass 本身,而不是 SomeClass 的一個(gè)實(shí)例。同樣,SomeProtocol.self 返回 SomeProtocol 本身,而不是運(yùn)行時(shí)符合 SomeProtocol 的某個(gè)類(lèi)型的實(shí)例。還可以對(duì)類(lèi)型的實(shí)例使用 type(of:) 表達(dá)式來(lái)獲取該實(shí)例在運(yùn)行階段的類(lèi)型,如下所示:
class SomeBaseClass {
class func printClassName() {
println("SomeBaseClass")
}
}
class SomeSubClass: SomeBaseClass {
override class func printClassName() {
println("SomeSubClass")
}
}
let someInstance: SomeBaseClass = SomeSubClass()
// someInstance 在編譯期是 SomeBaseClass 類(lèi)型,
// 但是在運(yùn)行期則是 SomeSubClass 類(lèi)型
type(of: someInstance).printClassName()
// 打印 “SomeSubClass”
更多信息可以查看 Swift 標(biāo)準(zhǔn)庫(kù)里的 type(of:)。
可以使用初始化表達(dá)式從某個(gè)類(lèi)型的元類(lèi)型構(gòu)造出一個(gè)該類(lèi)型的實(shí)例。對(duì)于類(lèi)實(shí)例,被調(diào)用的構(gòu)造器必須使用 required 關(guān)鍵字標(biāo)記,或者整個(gè)類(lèi)使用 final 關(guān)鍵字標(biāo)記。
class AnotherSubClass: SomeBaseClass {
let string: String
required init(string: String) {
self.string = string
}
override class func printClassName() {
print("AnotherSubClass")
}
}
let metatype: AnotherSubClass.Type = AnotherSubClass.self
let anotherInstance = metatype.init(string: "some string")
元類(lèi)型語(yǔ)法
類(lèi)型繼承子句被用來(lái)指定一個(gè)命名型類(lèi)型繼承自哪個(gè)類(lèi)、采納哪些協(xié)議。類(lèi)型繼承子句也用來(lái)指定一個(gè)類(lèi)類(lèi)型專(zhuān)屬協(xié)議。類(lèi)型繼承子句開(kāi)始于冒號(hào) :,其后是所需要的類(lèi)、類(lèi)型標(biāo)識(shí)符列表或兩者都有。
類(lèi)可以繼承單個(gè)超類(lèi),采納任意數(shù)量的協(xié)議。當(dāng)定義一個(gè)類(lèi)時(shí),超類(lèi)的名字必須出現(xiàn)在類(lèi)型標(biāo)識(shí)符列表首位,然后跟上該類(lèi)需要采納的任意數(shù)量的協(xié)議。如果一個(gè)類(lèi)不是從其它類(lèi)繼承而來(lái),那么列表可以以協(xié)議開(kāi)頭。關(guān)于類(lèi)繼承更多的討論和例子,請(qǐng)參閱 繼承。
其它命名型類(lèi)型可能只繼承或采納一系列協(xié)議。協(xié)議類(lèi)型可以繼承自任意數(shù)量的其他協(xié)議。當(dāng)一個(gè)協(xié)議類(lèi)型繼承自其它協(xié)議時(shí),其它協(xié)議中定義的要求會(huì)被整合在一起,然后從當(dāng)前協(xié)議繼承的任意類(lèi)型必須符合所有這些條件。正如在 協(xié)議聲明 中所討論的那樣,可以把 class 關(guān)鍵字放到協(xié)議類(lèi)型的類(lèi)型繼承子句的首位,這樣就可以聲明一個(gè)類(lèi)類(lèi)型專(zhuān)屬協(xié)議。
枚舉定義中的類(lèi)型繼承子句可以是一系列協(xié)議,或是枚舉的原始值類(lèi)型的命名型類(lèi)型。在枚舉定義中使用類(lèi)型繼承子句來(lái)指定原始值類(lèi)型的例子,請(qǐng)參閱 原始值。
類(lèi)型繼承子句語(yǔ)法
類(lèi)型繼承子句 → : 類(lèi)型繼承列表 類(lèi)型繼承列表 → 類(lèi)型標(biāo)識(shí)符 | 類(lèi)型標(biāo)識(shí)符 , 類(lèi)型繼承列表
Swift 廣泛使用類(lèi)型推斷,從而允許你省略代碼中很多變量和表達(dá)式的類(lèi)型或部分類(lèi)型。比如,對(duì)于 var x: Int = 0,你可以完全省略類(lèi)型而簡(jiǎn)寫(xiě)成 var x = 0,編譯器會(huì)正確推斷出 x 的類(lèi)型 Int。類(lèi)似的,當(dāng)完整的類(lèi)型可以從上下文推斷出來(lái)時(shí),你也可以省略類(lèi)型的一部分。比如,如果你寫(xiě)了 let dict: Dictionary = ["A" : 1],編譯器能推斷出 dict 的類(lèi)型是 Dictionary<String, Int>。
在上面的兩個(gè)例子中,類(lèi)型信息從表達(dá)式樹(shù)的葉子節(jié)點(diǎn)傳向根節(jié)點(diǎn)。也就是說(shuō),var x: Int = 0 中 x 的類(lèi)型首先根據(jù) 0 的類(lèi)型進(jìn)行推斷,然后將該類(lèi)型信息傳遞到根節(jié)點(diǎn)(變量 x)。
在 Swift 中,類(lèi)型信息也可以反方向流動(dòng)——從根節(jié)點(diǎn)傳向葉子節(jié)點(diǎn)。在下面的例子中,常量 eFloat 上的顯式類(lèi)型注解(: Float)將導(dǎo)致數(shù)字字面量 2.71828 的類(lèi)型是 Float 而非 Double。
let e = 2.71828 // e 的類(lèi)型會(huì)被推斷為 Double
let eFloat: Float = 2.71828 // eFloat 的類(lèi)型為 Float
Swift 中的類(lèi)型推斷在單獨(dú)的表達(dá)式或語(yǔ)句上進(jìn)行。這意味著所有用于類(lèi)型推斷的信息必須可以從表達(dá)式或其某個(gè)子表達(dá)式的類(lèi)型檢查中獲取到。