# 類型(Types)
Swift 語言存在兩種類型:命名型類型和復合型類型。*命名型類型*是指定義時可以給定名字的類型。命名型類型包括類、結構體、枚舉和協議。比如,一個用戶定義類 `MyClass` 的實例擁有類型 `MyClass`。除了用戶定義的命名型類型,Swift 標準庫也定義了很多常用的命名型類型,包括那些表示數組、字典和可選值的類型。
那些通常被其它語言認為是基本或原始的數據型類型,比如表示數字、字符和字符串的類型,實際上就是命名型類型,這些類型在 Swift 標準庫中是使用結構體來定義和實現的。因為它們是命名型類型,因此你可以按照 [擴展](../02_language_guide/20_Extensions.md) 和 [擴展聲明](./06_Declarations.md#extension-declaration) 中討論的那樣,聲明一個擴展來增加它們的行為以滿足你程序的需求。
*復合型類型*是沒有名字的類型,它由 Swift 本身定義。Swift 存在兩種復合型類型:函數類型和元組類型。一個復合型類型可以包含命名型類型和其它復合型類型。例如,元組類型 `(Int, (Int, Int))` 包含兩個元素:第一個是命名型類型 `Int`,第二個是另一個復合型類型 `(Int, Int)`。
你可以在命名型類型和復合型類型使用小括號。但是在類型旁加小括號沒有任何作用。舉個例子,`(Int)` 等同于 `Int`。
本節討論 Swift 語言本身定義的類型,并描述 Swift 中的類型推斷行為。
#### type {#type}
> 類型語法
>
> *類型* → [函數類型](#function-type)
>
> *類型* → [數組類型](#array-type)
>
> *類型* → [字典類型](#dictionary-type)
>
> *類型* → [類型標識](#type-identifier)
>
> *類型* → [元組類型](#tuple-type)
>
> *類型* → [可選類型](#optional-type)
>
> *類型* → [隱式解析可選類型](#implicitly-unwrapped-optional-type)
>
> *類型* → [協議合成類型](#protocol-composition-type)
>
> *類型* →[不透明類型](#opaque-type)
>
> *類型* → [元型類型](#metatype-type)
>
> *類型* → [自身類型](#self-type)
>
> *類型* → **Any**
>
> *類型* → **(** [類型](#type) **)**
## 類型注解 {#type-annotation-h}
*類型注解*顯式地指定一個變量或表達式的類型。類型注解從冒號 (`:`)開始, 以類型結尾,比如下面兩個例子:
```swift
let someTuple: (Double, Double) = (3.14159, 2.71828)
func someFunction(a: Int) { /* ... */ }
```
在第一個例子中,表達式 `someTuple` 的類型被指定為 `(Double, Double)`。在第二個例子中,函數 `someFunction` 的形參 `a` 的類型被指定為 `Int`。
類型注解可以在類型之前包含一個類型特性的可選列表。
> 類型注解語法
>
#### type-annotation {#type-annotation}
> *類型注解* → **:** [特性列表](./07_Attributes.md#attributes)<sub>可選</sub> **輸入輸出參數**<sub>可選</sub> [類型](#type)
## 類型標識符 {#type-identifier-h}
*類型標識符*可以引用命名型類型,還可引用命名型或復合型類型的別名。
大多數情況下,類型標識符引用的是與之同名的命名型類型。例如類型標識符 `Int` 引用命名型類型 `Int`,同樣,類型標識符 `Dictionary<String, Int>` 引用命名型類型 `Dictionary<String, Int>`。
在兩種情況下類型標識符不引用同名的類型。情況一,類型標識符引用的是命名型或復合型類型的類型別名。比如,在下面的例子中,類型標識符使用 `Point` 來引用元組 `(Int, Int)`:
```swift
typealias Point = (Int, Int)
let origin: Point = (0, 0)
```
情況二,類型標識符使用點語法(`.`)來表示在其它模塊或其它類型嵌套內聲明的命名型類型。例如,下面例子中的類型標識符引用在 `ExampleModule` 模塊中聲明的命名型類型 `MyType`:
```swift
var someValue: ExampleModule.MyType
```
> 類型標識符語法
>
#### type-identifier {#type-identifier}
> *類型標識符* → [類型名稱](#type-name) [泛型實參子句](./09_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可選</sub> | [類型名稱](#type-name) [泛型實參子句](./09_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可選</sub> **.** [類型標識符](#type-identifier)
#### type-name {#type-name}
> *類型名稱* → [標識符](./02_Lexical_Structure.md#identifier)
## 元組類型 {#tuple-type-h}
*元組類型*是使用括號括起來的零個或多個類型,類型間用逗號隔開。
你可以使用元組類型作為一個函數的返回類型,這樣就可以使函數返回多個值。你也可以命名元組類型中的元素,然后用這些名字來引用每個元素的值。元素的名字由一個標識符緊跟一個冒號 `(:)` 組成。[函數和多返回值](../02_language_guide/06_Functions.md#functions-with-multiple-return-values) 章節里有一個展示上述特性的例子。
當一個元組類型的元素有名字的時候,這個名字就是類型的一部分。
```swift
var someTuple = (top: 10, bottom: 12) // someTuple 的類型為 (top: Int, bottom: Int)
someTuple = (top: 4, bottom: 42) // 正確:命名類型匹配
someTuple = (9, 99) // 正確:命名類型被自動推斷
someTuple = (left: 5, right: 5) // 錯誤:命名類型不匹配
```
所有的元組類型都包含兩個及以上元素, 除了 `Void`。`Void` 是空元組類型 `()` 的別名。
> 元組類型語法
>
#### tuple-type {#tuple-type}
> *元組類型* → **(** **)** | **(** [元組類型元素](#tuple-type-element) **,** [元組類型元素列表](#tuple-type-element-list) **)**
>
#### tuple-type-element-list {#tuple-type-element-list}
> *元組類型元素列表* → [元組類型元素](#tuple-type-element) | [元組類型元素](#tuple-type-element) **,** [元組類型元素列表](#tuple-type-element-list)
>
#### tuple-type-element {#tuple-type-element}
> *元組類型元素* → [元素名](#element-name) [類型注解](#type-annotation) | [類型](#type)
>
#### element-name {#element-name}
> *元素名* → [標識符](./02_Lexical_Structure.md#identifier)
>
## 函數類型 {#function-type-h}
*函數類型*表示一個函數、方法或閉包的類型,它由形參類型和返回值類型組成,中間用箭頭(`->`)隔開:
> (`形參類型`)->(`返回值類型`)
*形參類型*是由逗號間隔的類型列表。由于*返回值類型*可以是元組類型,所以函數類型支持多返回值的函數與方法。
你可以對形參類型為 `() -> T`(其中 T 是任何類型)的函數使用 `autoclosure` 特性,這會在調用側隱式創建一個閉包。這從語法結構上提供了一種便捷:延遲對表達式的求值,直到其值在函數體中被調用。以自動閉包做為形參的函數類型的例子詳見 [自動閉包](../02_language_guide/07_Closures.md#autoclosures)。
函數類型可以擁有一個可變參數在*形參類型*中。從語法角度上講,可變參數由一個基礎類型名字緊隨三個點(`...`)組成,如 `Int...`。可變參數被認為是一個包含了基礎類型元素的數組。即 `Int...` 就是 `[Int]`。關于使用可變參數的例子,請參閱 [可變參數](../02_language_guide/06_Functions.md#variadic-parameters)。
為了指定一個 `in-out` 參數,可以在形參類型前加 `inout` 前綴。但是你不可以對可變參數或返回值類型使用 `inout`。關于這種形參的詳細講解請參閱 [輸入輸出參數](../02_language_guide/06_Functions.md#in-out-parameters)。
如果函數類型只有一個類型是元組類型的一個形參,那么元組類型在寫函數類型的時候必須用圓括號括起來。比如說,`((Int, Int)) -> Void` 是接收一個元組 `(Int, Int)` 作為形參并且不返回任何值的函數類型。與此相對,不加括號的 `(Int, Int) -> Void` 是一個接收兩個 `Int` 作為形參并且不返回任何值的函數類型。相似地,因為 `Void` 是空元組類型 `()` 的別名,函數類型 `(Void)-> Void` 與 `(()) -> ()` 是一樣的 - 一個將空元組作為唯一實參的函數。但這些類型和 `() -> ()` 是不一樣的 - 一個無實參的函數。
函數和方法中的實參名并不是函數類型的一部分。例如:
```swift
func someFunction(left: Int, right: Int) {}
func anotherFunction(left: Int, right: Int) {}
func functionWithDifferentLabels(top: Int, bottom: Int) {}
var f = someFunction // 函數 f 的類型為 (Int, Int) -> Void, 而不是 (left: Int, right: Int) -> Void.
f = anotherFunction // 正確
f = functionWithDifferentLabels // 正確
func functionWithDifferentArgumentTypes(left: Int, right: String) {}
f = functionWithDifferentArgumentTypes // 錯誤
func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {}
f = functionWithDifferentNumberOfArguments // 錯誤
```
由于實參標簽不是函數類型的一部分,你可以在寫函數類型的時候省略它們。
```swift
var operation: (lhs: Int, rhs: Int) -> Int // 錯誤
var operation: (_ lhs: Int, _ rhs: Int) -> Int // 正確
var operation: (Int, Int) -> Int // 正確
```
如果一個函數類型包涵多個箭頭(->),那么函數類型將從右向左進行組合。例如,函數類型 `(Int) -> (Int) -> Int` 可以理解為 `(Int) -> ((Int) -> Int)`,也就是說,該函數傳入 `Int`,并返回另一個傳入并返回 `Int` 的函數。
函數類型若要拋出或重拋錯誤就必須使用 `throws` 關鍵字來標記。`throws` 關鍵字是函數類型的一部分,非拋出函數是拋出函數的子類型。因此,在使用拋出函數的地方也可以使用不拋出函數。拋出和重拋函數的相關描述見章節 [拋出函數與方法](./06_Declarations.md#throwing-functions-and-methods) 和 [重拋函數與方法](./06_Declarations.md#rethrowing-functions-and-methods)。
### 對非逃逸閉包的限制 {#Restrictions for Nonescaping Closures}
當非逃逸閉包函數是形參時,不能存儲在屬性、變量或任何 `Any` 類型的常量中,因為這可能導致值的逃逸。
當非逃逸閉包函數是形參時,不能作為實參傳遞到另一個非逃逸閉包函數中。這樣的限制可以讓 Swift 在編譯時就完成更好的內存訪問沖突檢查,而不是在運行時。舉個例子:
```swift
let external: (Any) -> Void = { _ in () }
func takesTwoFunctions(first: (Any) -> Void, second: (Any) -> Void) {
first(first) // 錯誤
second(second) // 錯誤
first(second) // 錯誤
second(first) // 錯誤
first(external) // 正確
external(first) // 正確
}
```
在上面代碼里,`takesTwoFunctions(first:second:)` 的兩個形參都是函數。它們都沒有標記為 `@escaping`, 因此它們都是非逃逸的。
上述例子里的被標記為“錯誤”的四個函數調用會產生編譯錯誤。因為形參 `first` 和 `second` 是非逃逸函數,它們不能夠作為實參被傳遞到另一個非閉包函數。相對的, 標記“正確”的兩個函數不會產生編譯錯誤。這些函數調用不會違反限制,因為 `external` 不是 `takesTwoFunctions(first:second:)` 的形參之一。
如果你需要避免這個限制,標記其中一個形參為逃逸,或者使用 `withoutActuallyEscaping(_:do:)` 函數臨時轉換其中一個非逃逸函數形參為逃逸函數。關于避免內存訪問沖突,可以參閱 [內存安全](../02_language_guide/25_Memory_Safety.md)。
> 函數類型語法
>
#### function-type {#function-type}
> *函數類型* → [特性列表](./07_Attributes.md#attributes)<sub>可選</sub> [函數類型子句](#function-type-argument-clause) **throws**<sub>可選</sub> **->** [類型](#type)
#### function-type-argument-clause {#function-type-argument-clause}
> *函數類型子句* → **(**- **)**-
> *函數類型子句* → **(** [函數類型實參列表](#function-type-argument-list) *...*- <sub>可選</sub> **)**
#### function-type-argument-list {#function-type-argument-list}
> *函數類型實參列表* → [函數類型實參](#function-type-argument) | [函數類型實參](#function-type-argument), [函數類型實參列表](#function-type-argument-list)
#### function-type-argument {#function-type-argument}
> *函數類型實參* → [特性列表](./07_Attributes.md#attributes)<sub>可選</sub> **輸入輸出參數**<sub>可選</sub> [類型](#type) | [實參標簽](#argument-label) [類型注解](#type-annotation)
#### argument-label {#argument-label}
> *形參標簽* → [標識符](./02_Lexical_Structure.md#identifier)
## 數組類型 {#array-type-h}
Swift 語言為標準庫中定義的 `Array<Element>` 類型提供了如下語法糖:
> [`類型`]
>
換句話說,下面兩個聲明是等價的:
```swift
let someArray: Array<String> = ["Alex", "Brian", "Dave"]
let someArray: [String] = ["Alex", "Brian", "Dave"]
```
上面兩種情況下,常量 `someArray` 都被聲明為字符串數組。數組的元素也可以通過下標訪問:`someArray[0]` 是指第 0 個元素 `"Alex"`。
你也可以嵌套多對方括號來創建多維數組,最里面的方括號中指明數組元素的基本類型。比如,下面例子中使用三對方括號創建三維整數數組:
```swift
var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
```
訪問一個多維數組的元素時,最左邊的下標指向最外層數組的相應位置元素。接下來往右的下標指向第一層嵌入的相應位置元素,依次類推。這就意味著,在上面的例子中,`array3D[0]` 是 `[[1, 2], [3, 4]]`,`array3D[0][1]` 是 `[3, 4]`,`array3D[0][1][1]` 則是 `4`。
關于 Swift 標準庫中 `Array` 類型的詳細討論,請參閱 [數組](../02_language_guide/04_Collection_Types.md#arrays)。
> 數組類型語法
>
#### array-type {#array-type}
> *數組類型* → **[** [類型](#type) **]**
>
## 字典類型 {#dictionary-type-h}
Swift 語言為標準庫中定義的 `Dictionary<Key, Value>` 類型提供了如下語法糖:
> [`鍵類型` : `值類型`]
>
換句話說,下面兩個聲明是等價的:
```swift
let someDictionary: [String: Int] = ["Alex": 31, "Paul": 39]
let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]
```
上面兩種情況,常量 `someDictionary` 被聲明為一個字典,其中鍵為 `String` 類型,值為 `Int` 類型。
字典中的值可以通過下標來訪問,這個下標在方括號中指明了具體的鍵:`someDictionary["Alex"]` 返回鍵 `Alex` 對應的值。通過下標訪問會獲取對應值的可選類型。如果鍵在字典中不存在的話,則這個下標返回 `nil`。
字典中鍵的類型必須符合 Swift 標準庫中的 `Hashable` 協議。
關于 Swift 標準庫中 `Dictionary` 類型的詳細討論,請參閱 [字典](../02_language_guide/04_Collection_Types.md#dictionaries)。
> 字典類型語法
>
#### dictionary-type {#dictionary-type}
> *字典類型* → **[** [類型](#type) **:** [類型](#type) **]**
>
## 可選類型 {#optional-type-h}
Swift 定義后綴 `?` 來作為標準庫中定義的命名型類型 `Optional<Wrapped>` 的語法糖。換句話說,下面兩個聲明是等價的:
```swift
var optionalInteger: Int?
var optionalInteger: Optional<Int>
```
在上述兩種情況下,變量 `optionalInteger` 都被聲明為可選整型類型。注意在類型和 `?` 之間沒有空格。
類型 `Optional<Wrapped>` 是一個枚舉,有兩個成員,`none` 和 `some(Wrapped)`,用來表示可能有也可能沒有的值。任意類型都可以被顯式地聲明(或隱式地轉換)為可選類型。如果你在聲明可選變量或屬性的時候沒有提供初始值,它的值則會自動賦為默認值 `nil`。
如果一個可選類型的實例包含一個值,那么你就可以使用后綴運算符 `!` 來獲取該值,正如下面描述的:
```swift
optionalInteger = 42
optionalInteger! // 42
```
使用 `!` 運算符解包值為 `nil` 的可選值會導致運行錯誤。
你也可以使用可選鏈式調用和可選綁定來選擇性在可選表達式上執行操作。如果值為 `nil`,不會執行任何操作,因此也就沒有運行錯誤產生。
更多細節以及更多如何使用可選類型的例子,請參閱 [可選類型](../02_language_guide/01_The_Basics.md#optionals)。
> 可選類型語法
>
#### optional-type {#optional-type}
> *可選類型* → [類型](#type) **?**
>
## 隱式解析可選類型 {#implicitly-unwrapped-optional-type-h}
當可以被訪問時,Swift 語言定義后綴 `!` 作為標準庫中命名類型 `Optional<Wrapped>` 的語法糖,來實現自動解包的功能。如果嘗試對一個值為 `nil` 的可選類型進行隱式解包,將會產生運行時錯誤。因為隱式解包,下面兩個聲明等價:
```swift
var implicitlyUnwrappedString: String!
var explicitlyUnwrappedString: Optional<String>
```
注意類型與 `!` 之間沒有空格。
由于隱式解包會更改包含該類型的聲明語義,嵌套在元組類型或泛型中可選類型(比如字典元素類型或數組元素類型),不能被標記為隱式解包。例如:
```swift
let tupleOfImplicitlyUnwrappedElements: (Int!, Int!) // 錯誤
let implicitlyUnwrappedTuple: (Int, Int)! // 正確
let arrayOfImplicitlyUnwrappedElements: [Int!] // 錯誤
let implicitlyUnwrappedArray: [Int]! // 正確
```
由于隱式解析可選類型和可選類型有同樣的類型 `Optional<Wrapped>`,你可以在所有使用可選類型的地方使用隱式解析可選類型。比如,你可以將隱式解析可選類型的值賦給變量、常量和可選屬性,反之亦然。
正如可選類型一樣,如果你在聲明隱式解析可選類型的變量或屬性的時候沒有指定初始值,它的值則會自動賦為默認值 `nil`。
可以使用可選鏈式調用對隱式解析可選表達式選擇性地執行操作。如果值為 `nil`,就不會執行任何操作,因此也不會產生運行錯誤。
關于隱式解析可選類型的更多細節,請參閱 [隱式解析可選類型](../02_language_guide/01_The_Basics.md#implicityly-unwrapped-optionals)。
> 隱式解析可選類型語法
>
#### implicitly-unwrapped-optional-type {#implicitly-unwrapped-optional-type}
> *隱式解析可選類型* → [類型](#type) **!**
>
## 協議合成類型 {#protocol-composition-type-h}
*協議合成類型*定義了一種遵循協議列表中每個指定協議的類型,或者一個現有類型的子類并遵循協議列表中每個指定協議。協議合成類型只能用在類型注解、泛型形參子句和泛型 `where` 子句中指定類型。
協議合成類型的形式如下:
> `Protocol 1` & `Procotol 2`
協議合成類型允許你指定一個值,其類型遵循多個協議的要求而不需要定義一個新的命名型協議來繼承它想要符合的各個協議。比如,協議合成類型 `Protocol A & Protocol B & Protocol C` 等效于一個從 `Protocol A`,`Protocol B`,`Protocol C` 繼承而來的新協議。同樣的,你可以使用 `SuperClass & ProtocolA` 來取代聲明一個新的協議作為 `SuperClass` 的子類并遵循 `ProtocolA`。
協議合成列表中的每一項都必須是下面所列情況之一,列表中最多只能包含一個類:
- 類名
- 協議名
- 一個類型別名,它的潛在類型是一個協議合成類型、一個協議或者一個類
當協議合成類型包含類型別名時,同一個協議可能多次出現在定義中 — 重復被忽略。例如,下面代碼中定義的 `PQR` 等同于 `P & Q & R`。
```swift
typealias PQ = P & Q
typealias PQR = PQ & Q & R
```
> 協議合成類型語法
>
#### protocol-composition-type {#protocol-composition-type}
> *協議合成類型* → [協議標識符](#protocol-identifier) & [協議合成延續](#protocol-composition-continuation)
>
#### protocol-composition-continuation {#protocol-composition-continuation}
> *協議合成延續* → [協議標識符](#protocol-identifier) | [協議合成類型](#protocol-composition-type)
## 不透明類型 {#opaque-type-h}
*不透明類型*定義了遵循某個協議或者合成協議的類型,但不需要指明底層的具體類型。
不透明類型可以作為函數或下標的返回值,亦或是屬性的類型使用。
不透明類型不能作為元組類型的一部分或范型類型使用,比如數組元素類型或者可選值的包裝類型。
不透明類型的形式如下:
> some `constraint`
*constraint* 可以是類類型,協議類型,協議組合類型或者 `Any`。值只有當它遵循該協議或者組合協議,或者從該類繼承的時候,才能作為這個不透明類型的實例使用。和不透明值交互的代碼只能使用該值定義在 *constraint* 上的接口。
協議聲明里不能包括不透明類型。類不能使用不透明類型作為非 final 方法的返回值。
使用不透明類型作為返回值的函數必須返回單一公用底層類型。返回的類型可以包含函數范型類型形參的一部分。舉個例子,函數 `someFunction<T>()` 可以返回類型 `T` 或者 `Dictionary<String,T>` 的值。
> 不透明類型語法
#### opaque-type {#opaque-type}
> *不透明類型* → **some** [type](#type)
## 元類型 {#metatype-type-h}
*元類型*是指任意類型的類型,包括類類型、結構體類型、枚舉類型和協議類型。
類、結構體或枚舉類型的元類型是相應的類型名緊跟 `.Type`。協議類型的元類型——并不是運行時遵循該協議的具體類型——是該協議名字緊跟 `.Protocol`。比如,類 `SomeClass` 的元類型就是 `SomeClass.Type`,協議 `SomeProtocol` 的元類型就是 `SomeProtocal.Protocol`。
你可以使用后綴 `self` 表達式來獲取類型。比如,`SomeClass.self` 返回 `SomeClass` 本身,而不是 `SomeClass` 的一個實例。同樣,`SomeProtocol.self` 返回 `SomeProtocol` 本身,而不是運行時遵循 `SomeProtocol` 的某個類型的實例。還可以對類型的實例使用 `type(of:)` 表達式來獲取該實例動態的、在運行階段的類型,如下所示:
```swift
class SomeBaseClass {
class func printClassName() {
println("SomeBaseClass")
}
}
class SomeSubClass: SomeBaseClass {
override class func printClassName() {
println("SomeSubClass")
}
}
let someInstance: SomeBaseClass = SomeSubClass()
// someInstance 在編譯期是 SomeBaseClass 類型,
// 但是在運行期則是 SomeSubClass 類型
type(of: someInstance).printClassName()
// 打印“SomeSubClass”
```
更多信息可以查看 Swift 標準庫里的 [type(of:)](https://developer.apple.com/documentation/swift/2885064-type)。
可以使用初始化表達式從某個類型的元類型構造出一個該類型的實例。對于類實例,被調用的構造器必須使用 `required` 關鍵字標記,或者整個類使用 `final` 關鍵字標記。
```swift
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")
```
> 元類型語法
>
#### metatype-type {#metatype-type}
> *元類型* → [類型](#type) **.** **Type** | [類型](#type) **.** **Protocol**
## 自身類型 {#self-type-h}
`Self` 類型不是具體的類型,而是讓你更方便的引用當前類型,不需要重復或者知道該類的名字。
在協議聲明或者協議成員聲明時,`Self` 類型引用的是最終遵循該協議的類型。
在結構體,類或者枚舉值聲明時,Self 類型引用的是聲明的類型。在某個類型成員聲明時,Self 類型引用的是該類型。在類成員聲明時,`Self` 只能在以下幾種情況中出現:
* 作為方法的返回類型
* 作為只讀下標的返回類型
* 作為只讀計算屬性的類型
* 在方法體中
舉個例子,下面的代碼演示了返回值是 `Self` 的實例方法 `f` 。
```swift
class Superclass {
func f() -> Self { return self }
}
let x = Superclass()
print(type(of: x.f()))
// 打印 "Superclass"
class Subclass: Superclass { }
let y = Subclass()
print(type(of: y.f()))
// 打印 "Subclass"
let z: Superclass = Subclass()
print(type(of: z.f()))
// 打印 "Subclass"
```
上面例子的最后一部分表明 `Self` 引用的是值 `z` 的運行時類型 `Subclass` ,而不是變量本身的編譯時類型 `Superclass` 。
在嵌套類型聲明時,`Self` 類型引用的是最內層聲明的類型。
`Self` 類型引用的類型和 Swift 標準庫中 [type(of:)](https://developer.apple.com/documentation/swift/2885064-type) 函數的結果一樣。使用 `Self.someStaticMember` 訪問當前類型中的成員和使用 `type(of: self).someStaticMember` 是一樣的。
> 自身類型語法
#### self-type{#self-type}
> *自身類型* → **Self**
## 類型繼承子句 {#type-inheritance-clause-h}
*類型繼承子句*被用來指定一個命名型類型繼承自哪個類、采納哪些協議。類型繼承子句開始于冒號 `:`,其后是類型標識符列表。
類可以繼承自單個超類,并遵循任意數量的協議。當定義一個類時,超類的名字必須出現在類型標識符列表首位,然后跟上該類需要遵循的任意數量的協議。如果一個類不是從其它類繼承而來,那么列表可以以協議開頭。關于類繼承更多的討論和例子,請參閱 [繼承](../02_language_guide/13_Inheritance.md)。
其它命名型類型只能繼承自或采納一系列協議。協議類型可以繼承自任意數量的其他協議。當一個協議類型繼承自其它協議時,其它協議中定義的要求會被整合在一起,然后從當前協議繼承的任意類型必須符合所有這些條件。
枚舉定義中的類型繼承子句可以是一系列協議,或者是指定單一的命名類型,此時枚舉為其用例分配原始值。在枚舉定義中使用類型繼承子句來指定原始值類型的例子,請參閱 [原始值](../02_language_guide/08_Enumerations.md#raw-values)。
> 類型繼承子句語法
>
#### type-inheritance-clause {#type-inheritance-clause}
> *類型繼承子句* → **:** [類型繼承列表](#type-inheritance-list)
>
#### type-inheritance-list {#type-inheritance-list}
> *類型繼承列表* → [類型標識符](#type-identifier) | [類型標識符](#type-identifier) **,** [類型繼承列表](#type-inheritance-list)
## 類型推斷
Swift 廣泛使用*類型推斷*,從而允許你省略代碼中很多變量和表達式的類型或部分類型。比如,對于 `var x: Int = 0`,你可以完全省略類型而簡寫成 `var x = 0`,編譯器會正確推斷出 `x` 的類型 `Int`。類似的,當完整的類型可以從上下文推斷出來時,你也可以省略類型的一部分。比如,如果你寫了 `let dict: Dictionary = ["A" : 1]`,編譯器能推斷出 `dict` 的類型是 `Dictionary<String, Int>`。
在上面的兩個例子中,類型信息從表達式樹的葉子節點傳向根節點。也就是說,`var x: Int = 0` 中 `x` 的類型首先根據 `0` 的類型進行推斷,然后將該類型信息傳遞到根節點(變量 `x`)。
在 Swift 中,類型信息也可以反方向流動——從根節點傳向葉子節點。在下面的例子中,常量 `eFloat` 上的顯式類型注解(`: Float`)將導致數字字面量 `2.71828` 的類型是 `Float` 而非 `Double`。
```swift
let e = 2.71828 // e 的類型會被推斷為 Double
let eFloat: Float = 2.71828 // eFloat 的類型為 Float
```
Swift 中的類型推斷在單獨的表達式或語句上進行。這意味著所有用于類型推斷的信息必須可以從表達式或其某個子表達式的類型檢查中獲取到。
- 1.關于 Swift
- 2.Swift 初見
- 2-1基礎部分
- 2-2基本運算符
- 2-3字符串和字符
- 2-4集合類型
- 2-5控制流
- 2-6函數
- 2-7閉包
- 2-8枚舉
- 2-9類和結構體
- 2-10屬性
- 2-11方法
- 2-12下標
- 2-13繼承
- 2-14構造過程
- 2-15析構過程
- 2-16可選鏈
- 2-17錯誤處理
- 2-18類型轉換
- 2-19嵌套類型
- 2-20擴展
- 2-21協議
- 2-22泛型
- 2-23不透明類型
- 2-24自動引用計數
- 2-25內存安全
- 2-26訪問控制
- 2-27高級運算符
- 3-1關于語言參考
- 3-2詞法結構
- 3-3類型
- 3-4表達式
- 3-5語句
- 3-6聲明
- 3-7特性
- 3-8模式
- 3-9泛型參數
- 4語法總結