@ -18,6 +18,7 @@
- [元组类型( Tuple Type) ](#tuple_type )
- [函数类型( Function Type) ](#function_type )
- [数组类型( Array Type) ](#array_type )
- [字典类型( Dictionary Type) ](#dictionary_type )
- [可选类型( Optional Type) ](#optional_type )
- [隐式解析可选类型( Implicitly Unwrapped Optional Type) ](#implicitly_unwrapped_optional_type )
- [协议合成类型( Protocol Composition Type) ](#protocol_composition_type )
@ -25,223 +26,239 @@
- [类型继承子句( Type Inheritance Clause) ](#type_inheritance_clause )
- [类型推断( Type Inference) ](#type_inference )
Swift 语言存在两种类型: 命名型类型和复合型类型。命名型类型是指定义时可以给定名字的类型。命名型类型包括类、结构体、枚举和协议。比如, 一个用户定义的类MyClass的实例拥有类型MyClass。除了用户定义的命名型类型, Swift 标准库也定义了很多常用的命名型类型,包括那些表示数组、字典和可选值的类型。
Swift 语言存在两种类型:命名型类型和复合型类型。命名型类型是指定义时可以给定名字的类型。命名型类型包括类、结构体、枚举和协议。比如,一个用户定义的类 MyClass 的实例拥有类型 MyClass。除了用户定义的命名型类型, Swift 标准库也定义了很多常用的命名型类型,包括那些表示数组、字典和可选值的类型。
那些通常被其它语言认为是基本或初级 的数据型类型( Data types) —— 比如表示数字、字符和字符串的类型—— 实际上就是命名型类型, 这些类型在Swift 标准库中是使用结构体来定义和实现的。因为它们是命名型类型,因此你可以按照“扩展和扩展声明”章节里讨论的那样,声明一个扩展来增加它们的行为以迎合你程序的需求。
那些通常被其它语言认为是基本或原始 的数据型类型, 比如表示数字、字符和字符串的类型, 实际上就是命名型类型,这些类型在 Swift 标准库中是使用结构体来定义和实现的。因为它们是命名型类型,因此你可以按照“扩展和扩展声明”章节里讨论的那样,声明一个扩展来增加它们的行为以迎合你程序的需求。
* 复合型类型* 是没有名字的类型,它由 Swift 本身定义。Swift 存在两种复合型类型:函数类型和元组类型。一个复合型类型可以包含命名型类型和其它复合型类型。例如,元组类型(Int, (Int, Int))包含两个元素: 第一个是命名型类型Int, 第二个是另一个复合型类型(Int, Int).
复合型类型是没有名字的类型,它由 Swift 本身定义。Swift 存在两种复合型类型:函数类型和元组类型。一个复合型类型可以包含命名型类型和其它复合型类型。例如,元组类型 ` (Int, (Int, Int))` 包含两个元素:第一个是命名型类型 ` Int` ,第二个是另一个复合型类型 ` (Int, Int)` 。
本节讨论 Swift 语言本身定义的类型,并描述 Swift 中的类型推断行为。
> 类型语法
> *类型* → [*数组类型*](#array_type) | [*字典类型*](../chapter3/03_Types.html#dictionary_type) | [*函数类型*](../chapter3/03_Types.html#function_type) | [*类型标识*](../chapter3/03_Types.html#type_identifier) | [*元组类型*](../chapter3/03_Types.html#tuple_type) | [*可选类型*](../chapter3/03_Types.html#optional_type) | [*隐式解析可选类型*](../chapter3/03_Types.html#implicitly_unwrapped_optional_type) | [*协议合成类型*](../chapter3/03_Types.html#protocol_composition_type) | [*元型类型*](../chapter3/03_Types.html#metatype_type)
< a name = "type" ></ a >
> *类型* → [*数组类型*](#array_type) | [*字典类型*](#dictionary_type) | [*函数类型*](#function_type) | [*类型标识*](#type_identifier) | [*元组类型*](#tuple_type) | [*可选类型*](#optional_type) | [*隐式解析可选类型*](#implicitly_unwrapped_optional_type) | [*协议合成类型*](#protocol_composition_type) | [*元型类型*](#metatype_type)
< a name = "type_annotation" ></ a >
##类型注解
## 类型注解
类型注解显式地指定一个变量或表达式的值。类型注解始于冒号`:` 终于类型,比如下面两个例子:
类型注解显式地指定一个变量或表达式的值。类型注解始于冒号 `:` 终于类型,比如下面两个例子:
```swift
let someTuple : ( Double , Double ) = ( 3.14159 , 2.71828 )
func someFunction ( a : Int ){ /* ... */ }
func someFunction ( a : Int ) { /* ... */ }
```
在第一个例子中,表达式`someTuple` 的类型被指定为`(Double, Double)` 。在第二个例子中,函数`someFunction` 的参数`a` 的类型被指定为`Int` 。
在第一个例子中,表达式 `someTuple` 的类型被指定为 `(Double, Double)` 。在第二个例子中,函数 `someFunction` 的参数 `a` 的类型被指定为 `Int` 。
类型注解可以在类型之前包含一个类型特性( type attributes) 的可选列表。
类型注解可以在类型之前包含一个类型特性的可选列表。
> 类型注解语法
> *类型注解* → **:** [*特性(Attributes) 列表*](../chapter3/06_Attributes.html#attributes) _可选_ [*类型*](../chapter3/03_Types.html #type)
> *类型注解* → **:** [*特性列表*](../chapter3/06_Attributes.html#attributes)<sub>可选</sub> [*类型*]( #type)
< a name = "type_identifier" ></ a >
##类型标识符
## 类型标识符
类型标识符引用命名型类型或者是 命名型/ 复合型类型的别名。
类型标识符引用命名型类型,还可引用 命名型或 复合型类型的别名。
大多数情况下,类型标识符引用的是与之同名的命名型类型。例如类型标识符`Int` 引用命名型类型`Int` ,同样,类型标识符`Dictionary<String, Int>` 引用命名型类型`Dictionary<String, Int>` 。
大多数情况下,类型标识符引用的是与之同名的命名型类型。例如类型标识符 `Int` 引用命名型类型 `Int` ,同样,类型标识符 `Dictionary<String, Int>` 引用命名型类型 `Dictionary<String, Int>` 。
在两种情况下类型标识符不引用同名的类型。情况一,类型标识符引用的是命名型/ 复合型类型的类型别名。比如,在下面的例子中,类型标识符使用`Point` 来引用元组`(Int, Int)` :
在两种情况下类型标识符不引用同名的类型。情况一,类型标识符引用的是命名型或 复合型类型的类型别名。比如,在下面的例子中,类型标识符使用 `Point` 来引用元组 `(Int, Int)` :
```swift
typealias Point = ( Int , Int )
let origin : Point = ( 0 , 0 )
```
情况二,类型标识符使用dot( `.` )语法 来表示在其它模块( modules) 或其它类型嵌套内声明的命名型类型。例如,下面例子中的类型标识符引用在`ExampleModule` 模块中声明的命名型类型`MyType` :
情况二,类型标识符使用点语法( `.` ) 来表示在其它模块或其它类型嵌套内声明的命名型类型。例如,下面例子中的类型标识符引用在 `ExampleModule` 模块中声明的命名型类型 `MyType` :
```swift
var someValue : ExampleModule . MyType
```
> 类型标识语法
> *类型标识* → [*类型名称*](../chapter3/03_Types.html #type_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_ | [*类型名称*](../chapter3/03_Types.html #type_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_ **.** [*类型标识*](../chapter3/03_Types.html #type_identifier)
> *类名* → [*标识符*](LexicalStructure.html#identifier)
> 类型标识符 语法
> *类型标识符 * → [*类型名称*](#type_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_argument_clause)<sub>可选</sub> | [*类型名称*]( #type_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_argument_clause)<sub>可选</sub> **.** [*类型标识符 *](#type_identifier)
< a name = "type_name" ></ a >
> *类型名称* → [*标识符*](LexicalStructure.html#identifier)
< a name = "tuple_type" ></ a >
##元组类型
## 元组类型
元组类型使用逗号隔开并 使用括号括起来的0 个或多个类型组成的列表 。
元组类型是 使用括号括起来的零 个或多个类型,类型间用逗号隔开 。
你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号`(:)` 组成。“ 函数和多返回值” 章节里有一个展示上述特性的例子。
你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号 `(:)` 组成。[ 函数和多返回值 ](../chapter2/06_Functions.html#functions_with_multiple_return_values ) 章节里有一个展示上述特性的例子。
`v oid` 是空元组类型`()` 的别名。如果括号内只有一个元素,那么该类型就是括号内元素的类型。比如,`(Int)` 的类型是`Int` 而不是`(Int)` 。所以,只有当元组类型包含的元素个数在两个及以上时才可以命名元组元素。
`V oid` 是空元组类型 `()` 的别名。如果括号内只有一个元素,那么该类型就是括号内元素的类型。比如,`(Int)` 的类型是 `Int` 而不是 `(Int)` 。所以,只有当元组类型包含的元素个数在两个及以上时才可以命名元组元素。
> 元组类型语法
> *元组类型* → **(** [*元组类型主体*](../chapter3/03_Types.html #tuple_type_body) _可选_ **)**
> *元组类型主体* → [*元组类型的元素列表*](../chapter3/03_Types.html#tuple_type_element_list) **...** _可选_
> *元组类型的元素列表 * → [*元组类型的 元素*](../chapter3/03_Types.html#tuple_type_element) | [*元组类型的元素*](../chapter3/03_Types.html#tuple_type_element) **,** [*元组类型的元素列表*](../chapter3/03_Types.html #tuple_type_element_list)
> *元组类型的元素* → [*特性(Attributes)列表*](../chapter3/06_Attributes.html#attributes) _可选_ **inout** _可选_ [*类型*](../chapter3/03_Types.html#type) | **inout** _可选_ [*元素名*](../chapter3/03_Types.html#element_name) [*类型注解*](../chapter3/03_Types.html#type_annotation)
> *元组类型* → **(** [*元组类型主体*](#tuple_type_body)<sub>可选</sub> **)**
< a name = "tuple_type_body" ></ a >
> *元组类型主体 * → [*元组类型元素列表 *](#tuple_type_element_list) **...**<sub>可选</sub>
< a name = "tuple_type_element_list" ></ a >
> *元组类型元素列表* → [*元组类型元素*](#tuple_type_element) | [*元组类型元素*](#tuple_type_element) **,** [*元组类型元素列表*](#tuple_type_element_list)
< a name = "tuple_type_element" ></ a >
> *元组类型元素* → [*特性列表*](../chapter3/06_Attributes.html#attributes)<sub>可选</sub> **inout**<sub>可选</sub> [*类型*](#type) | **inout**<sub>可选</sub> [*元素名*](#element_name) [*类型注解*](#type_annotation)
< a name = "element_name" ></ a >
> *元素名* → [*标识符*](LexicalStructure.html#identifier)
< a name = "function_type" ></ a >
##函数类型
## 函数类型
函数类型表示一个函数、方法或闭包的类型,它由一个 参数类型和返回值类型组成,中间用箭头`->` 隔开:
函数类型表示一个函数、方法或闭包的类型,它由参数类型和返回值类型组成,中间用箭头( `->` ) 隔开:
`parameter type` -> `return type `
`参数类型` -> `返回值类型 `
由于 * 参数类型* 和 * 返回值类型* 可以是元组类型,所以函数类型支持多参数与多返回值的函数与方法。。
由于参数类型和 返回值类型可以是元组类型,所以函数类型支持多参数与多返回值的函数与方法。
对于参数类型是空元组类型`()` 以及返回值类型为表达式类型的函数类型,你可以对其参数声明 使用`autoclosure` (见声明属性章节)。一个自动闭包函数捕获特定表达式上的隐式闭包而非表达式本身 。这从语法结构上提供了一种便捷:延迟对表达式的求值,直到在函数体中有 使用它的值 。以自动闭包函数类型 做为参数的例子详见 [自动闭包( Autoclosures) ](TODO: 添加链接 ) 。
你可以对函数参数 使用 `autoclosure` 特性。这会自动将参数表达式转化为闭包,表达式的结果即闭包返回值 。这从语法结构上提供了一种便捷:延迟对表达式的求值,直到其值 在函数体中被 使用。以自动闭包做为参数的函数类型 的例子详见 [自动闭包 ](../chapter2/07_Closures.html#autoclosures ) 。
函数类型可以拥有一个可变长参数作为参数类型中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字紧随三个点`( ...) ` 组成,如`Int...` 。可变长参数被认为是一个包含了基础类型元素的数组。即`Int...` 就是`[Int]` 。关于使用可变长参数的例子,见章节[V ariadic P arameters ](TODO: 添加链接 )。
函数类型可以拥有一个可变长参数作为参数类型中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字紧随三个点( `...` ) 组成,如 `Int...` 。可变长参数被认为是一个包含了基础类型元素的数组。即 `Int...` 就是 `[Int]` 。关于使用可变长参数的例子,请参阅 [可变参数 ](../chapter2/06_Functions.html#v ariadic_p arameters )。
为了指定一个`in-out` 参数,可以在参数类型前加`inout` 前缀。但是你不可以对可变长参数或返回值类型使用`inout` 。关于In-Out参数的讨论见章节[In-Out参数部分 ](TODO: 添加链接 )。
为了指定一个 `in-out` 参数,可以在参数类型前加 `inout` 前缀。但是你不可以对可变长参数或返回值类型使用 `inout` 。关于这种参数的详细讲解请参阅 [输入输出参数 ](../chapter2/06_Functions.html#in_out_parameters )。
柯里化函数( Curried fuction) 的函数类型从右向左递归地组成一组 。例如,函数类型`Int -> Int -> Int` 可以被 理解为`Int -> (Int -> Int)` —— 也就是说,一个函数 的参数为`Int` 类型,其返回类型是一个参数类型为`Int` 返回类型为`Int` 的函数类型。关于柯里化函数的讨论见章节[C urried Fu ctions](TODO: 添加链接 )。
柯里化函数( Curried fuction) 的函数类型从右向左进行组合 。例如,函数类型 `Int -> Int -> Int` 可以理解为 `Int -> (Int -> Int)` , 也就是说,该函数类型 的参数为 `Int` 类型,其返回类型是一个参数类型为 `Int` , 返回类型为 `Int` 的函数类型。关于柯里化函数的讨论见章节 [柯里化函数 ](05_Declarations.html#c urried_fun ctions )。
函数类型若要抛出错误就必须使用`throws` 关键字来标记,若要重抛错误则必须使用`rethrows` 关键字来标记。`throws` 关键字是函数类型的一部分, 不抛出函数( nonthrowing function) 是抛出函数( throwing function) 函数的一个子类型。因此, 在使用抛出函数的地方也可以使用不抛出函数。对于柯里化函数, `throws` 关键字只应用于最里层的函数。抛出和重抛函数( rethrowing function) 的相关描述见章节[抛出函数与方法 ](TODO: 添加链接 )和[重抛函数与方法 ](TODO: 添加链接 )。
函数类型若要抛出错误就必须使用 `throws` 关键字来标记,若要重抛错误则必须使用 `rethrows` 关键字来标记。`throws` 关键字是函数类型的一部分, 不抛出函数( nonthrowing function) 是抛出函数( throwing function) 函数的一个子类型。因此, 在使用抛出函数的地方也可以使用不抛出函数。对于柯里化函数, `throws` 关键字只应用于最里层的函数。抛出和重抛函数( rethrowing function) 的相关描述见章节 [抛出函数与方法 ](05_Declarations.html#throwing_functions_and_methods ) 和 [重抛函数与方法 ](05_Declarations.html#rethrowing_functions_and_methods )。
> 函数类型语法
> *函数类型* → [*类型*](../chapter3/03_Types.html#type) _抛出_ _可选_ **->** [*类型*](../chapter3/03_Types.html #type)
> *函数类型* → [*类型*](../chapter3/03_Types.html#type)_重抛_ **->** [*类型*](../chapter3/03_Types.html #type)
> *函数类型* → [*类型*](#type) **throws**<sub>可选</sub> **->** [*类型*]( #type)
> *函数类型* → [*类型*](#type) **rethrows**<sub>可选</sub> **->** [*类型*]( #type)
< a name = "array_type" ></ a >
##数组类型
## 数组类型
Swift 语言为标准库中定义的 `Array<Element>` 类型提供了如下语法糖:
[`类型` ]
Swift语言中使用[`type` ]来简化标准库中定义`Array<T>` 类型的操作。
换句话说,下面两个声明是等价的:
```swift
let someArray : [ String ] = [ "Alex" , "Brian" , "Dave" ]
let someArray : Array < String > = [ "Alex" , "Brian" , "Dave" ]
let someArray : [ String ] = [ "Alex" , "Brian" , "Dave" ]
```
上面两种情况下,常量`someArray` 都被声明为字符串数组。数组的元素也可以通过`[]` 获取访问:`someArray[0]` 是指第0个元素`“Alex”` 。
你也可以嵌套多对方括号来创建多维数组,最里面的方括号中指明数组元素的基本类型。比如,下面例子中使用三对方括号创建三维整数数组 。
上面两种情况下,常量 `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标准库中 `A rray` 类型的细节讨论,见章节[Arrays ](TODO: 添加链接 ) 。
访问一个多维数组的元素时,最左边的下标指向最外层数组的相应位置元素。接下来往右的下标指向第一层嵌入的相应位置元素,依次类推。这就意味着,在上面的例子中, `a rray3D[0]` 是 `[[1, 2], [3, 4]]` , `array3D[0][1]` 是 `[3, 4]` , `array3D[0][1][1]` 则是 `4` 。
关于 Swift 标准库中 `Array` 类型的详细讨论,请参阅 [数组 ](../chapter2/04_Collection_Types.html#arrays )。
> 数组类型语法
> *数组类型* → [*类型*](../chapter3/03_Types.html #type)
> *数组类型* → **[** [*类型*](#type) **]**
< a name = "dictionary_type" ></ a >
##字典类型
## 字典类型
Swift 语言为标准库中定义的 `Dictionary<Key, Value>` 类型提供了如下语法糖:
[`键类型` : `值类型` ]
Swift语言中使用[`key type: value type` ]来简化标准库中定义`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` 。
上面两种情况,常量 `someDictionary` 被声明为一个字典,其中键为 `String` 类型,值为 `Int` 类型 。
字典中键的类型必须遵循Swift标准库中的可哈希协议 。
字典中的值可以通过下标来访问,这个下标在方括号中指明了具体的键:`someDictionary["Alex"]` 返回键 `Alex` 对应的值。如果键在字典中不存在的话,则这个下标返回 `nil` 。
关于 Swift标准库中`Dictionary` 类型的更多细节可查看章节[Dictionaries ](TODO: 添加链接 ) 。
字典中键的类型必须符合 Swift 标准库中的 `Hashable` 协议 。
关于 Swift 标准库中 `Dictionary` 类型的详细讨论,请参阅 [字典 ](../chapter2/04_Collection_Types.html#dictionaries )。
> 字典类型语法
> *字典类型* → **[**[*类型*](../chapter3/03_Types.html#type) **:** [*类型*](../chapter3/03_Types.html #type) **]**
> *字典类型* → **[** [*类型*](#type) **:** [*类型*]( #type) **]**
< a name = "optional_type" ></ a >
##可选类型
## 可选类型
Swift定义后缀`?` 来作为标准库中的定义的命名型类型`Optional<T>` 的简写 。换句话说,下面两个声明是等价的:
Swift 定义后缀 `?` 来作为标准库中的定义的命名型类型 `Optional<Wrapped>` 的语法糖 。换句话说,下面两个声明是等价的:
```swift
var optionalInteger : Int ?
var optionalInteger : Optional < Int >
```
在上述两种情况下,变量`optionalInteger` 都被声明为可选整型类型。注意在类型和`?` 之间没有空格。
类型 `O ptional<T>` 是一个枚举,有两种形式,`None` 和`Some(T)` ,又来代表可能出现或可能不出现的值。任意类型都可以被显式的声明(或隐式的转换)为可选类型。当声明一个可选类型时,确保使用括号给`?` 提供合适的作用范围。比如说,声明一个整型的可选数组,应写作`(Int[])?` ,写成`Int[]?` 的话则会出错 。
在上述两种情况下,变量 `o ptionalInteger` 都被声明为可选整型类型。注意在类型和 `?` 之间没有空格 。
如果你在声明或定义可选变量或特 性的时候没有提供初始值,它的值则会自动赋成缺省值 `nil` 。
类型 `Optional<Wrapped>` 是一个枚举,有两个成员,`None` 和 `Some(Wrapped)` ,用来表示可能有也可能没有的值。任意类型都可以被显式地声明(或隐式地转换)为可选类型。 如果你在声明或定义可选变量或属 性的时候没有提供初始值,它的值则会自动赋为默认值 `nil` 。
如果一个可选类型的实例包含一个值,那么你就可以使用后缀操作符 `!` 来获取该值,正如下面描述的:
如果一个可选类型的实例包含一个值,那么你就可以使用后缀运算符 `!` 来获取该值,正如下面描述的:
```swift
optionalInteger = 42
optionalInteger ! // 42
optionalInteger ! // 42
```
使用`!` 操作符获取值为`nil` 的可选项会导致运行错误( runtime error) 。
你也可以使用可选链和可选绑定来选择性的执行可选表达式上的操作。如果 值为`nil` ,不会执行任何操作因此也就没有 运行错误产生 。
使用 `!` 运算符解包 值为 `nil` 的可选值会导致 运行错误。
更多细节以及更多如何使用可选类型的例子,见章节[Optionals ](TODO: 添加链接 ) 。
你也可以使用可选链式调用和可选绑定来选择性地在可选表达式上执行操作。如果值为 `nil` ,不会执行任何操作,因此也就没有运行错误产生 。
更多细节以及更多如何使用可选类型的例子,请参阅 [可选类型 ](../chapter2/01_The_Basics.html#optionals )。
> 可选类型语法
> *可选类型* → [*类型*](../chapter3/03_Types.html #type) **?**
> *可选类型* → [*类型*](#type) **?**
< a name = "implicitly_unwrapped_optional_type" ></ a >
##隐式解析可选类型
## 隐式解析可选类型
Swift语言定义后缀`!` 作为标准库中命名类型`ImplicitlyUnwrappedOptional<T>` 的简写 。换句话说,下面两个声明等价:
Swift 语言定义后缀 `!` 作为标准库中命名类型 `ImplicitlyUnwrappedOptional<Wrapped>` 的语法糖 。换句话说,下面两个声明等价:
```swift
var implicitlyUnwrappedString : String !
var implicitlyUnwrappedString : ImplicitlyUnwrappedOptional < String >
```
上述两种情况下,变量`implicitlyUnwrappedString` 被声明为一个隐式解析可选类型的字符串。注意类型与`!` 之间没有空格。
你可以在使用可选类型的地方同样使用隐式解析可选类型。比如,你可以将隐式解析可选类型的值赋给变量、常量和可选特性,反之亦然 。
上述两种情况下,变量 `implicitlyUnwrappedString` 被声明为一个隐式解析可选类型的字符串。注意类型与 `!` 之间没有空格 。
有了可选,你在声明隐式解析可选变量或特性的时候就不用指定初始值,因为它有缺省值`nil` 。
你可以在使用可选类型的地方使用隐式解析可选类型。比如,你可以将隐式解析可选类型的值赋给变量、常量和可选属性,反之亦然 。
由于隐式解析可选的值会在使用时自动解析,所以没必要使用操作符`!` 来解析它。也就是说,如果你使用值为`nil` 的隐式解析可选,就会导致运行错误 。
正如可选类型一样,你在声明隐式解析可选类型的变量或属性的时候也不用指定初始值,因为它有默认值 `nil` 。
使用可选链会选择性的执行隐式解析可选表达式上的某一个操作。如果 值为`nil` ,就不会执行任何操作,因此也不会产生 运行错误。
由于隐式解析可选类型的值会在使用时自动解析,所以没必要使用操作符 `!` 来解析它。也就是说,如果你使用 值为 `nil` 的隐式解析可选类型,就会导致 运行错误。
关于隐式解析可选的更多细节,见章节[Implicitly Unwrapped Optionals ](TODO: 添加链接 ) 。
可以使用可选链式调用来在隐式解析可选表达式上选择性地执行操作。如果值为 `nil` ,就不会执行任何操作,因此也不会产生运行错误 。
> 隐式解析可选类型(I mplicitly U nwrapped O ptional Type)语法
> *隐式解析可选类型* → [*类型*](../chapter3/03_Types.html#type) **!**
关于隐式解析可选类型的更多细节,请参阅 [隐式解析可选类型 ](../chapter2/01_The_Basics.html#i mplicity ly_u nwrapped_o ptionals )。
> 隐式解析可选类型语法
> *隐式解析可选类型* → [*类型*](#type) **!**
< a name = "protocol_composition_type" ></ a >
##协议合成类型
## 协议合成类型
协议合成类型是一种遵循具体 协议列表中每个协议的类型。协议合成类型可能会用在类型注解和泛型参数中。
协议合成类型是一种符合 协议列表中每个指定 协议的类型。协议合成类型可能会用在类型注解和泛型参数中。
协议合成类型的形式如下:
```swift
protocol < Protocol 1 , Procotol 2 >
```
protocol< `Protocol 1` , `Procotol 2` >
协议合成类型允许你指定一个值,其类型遵循 多个协议的条件 且不需要定义一个新的命名型协议来继承其 它想要遵循 的各个协议。比如,协议合成类型`protocol<Protocol A, Protocol B, Protocol C>` 等效于一个从`Protocol A` , `Protocol B` , `Protocol C` 继承而来的新协议`Protocol D` ,很显然这样做有效率的多,甚至不需引入一个新名字。
协议合成类型允许你指定一个值,其类型符合 多个协议的要求 且不需要定义一个新的命名型协议来继承它想要符合 的各个协议。比如,协议合成类型 `protocol<Protocol A, Protocol B, Protocol C>` 等效于一个从 `Protocol A` , `Protocol B` , `Protocol C` 继承而来的新协议 `Protocol D` ,很显然这样做有效率的多,甚至不需引入一个新名字。
协议合成列表中的每项必须是协议名或协议合成类型的类型别名。如果列表为空,它就会指定一个空协议合成列表,这样 每个类型都能遵循 。
协议合成列表中的每项必须是协议名或协议合成类型的类型别名。如果列表为空,它就会指定一个空协议合成列表,每个类型都符合它 。
> 协议合成类型语法
> *协议合成类型* → **protocol** **<** [*协议标识符列表*](../chapter3/03_Types.html #protocol_identifier_list) _可选_ **>**
> *协议标识符列表* → [*协议标识符*](../chapter3/03_Types.html#protocol_identifier) | [*协议标识符*](../chapter3/03_Types.html#protocol_identifier) **,** [*协议标识符列表*](../chapter3/03_Types.html# protocol_identifier_list)
> *协议标识符* → [*类型 标识*](../chapter3/03_Types.html#type _identifier)
> *协议合成类型* → **protocol** **<** [*协议标识符列表*](#protocol_identifier_list)<sub>可选</sub> **>**
< a name = " protocol_identifier_list" ></ a >
> *协议标识符列表 * → [*协议 标识符 *](#protocol_identifier) | [*协议标识符*](#protocol_identifier) **,** [*协议标识符列表*](#protocol _identifier_list )
< a name = "protocol_identifier" ></ a >
> *协议标识符* → [*类型标识符*](#type_identifier)
< a name = "metatype_type" ></ a >
##元类型
## 元类型
元类型是指所有 类型的类型,包括类、结构体、枚举和协议。
元类型是指类型的类型,包括类类型 、结构体类型 、枚举类型 和协议类型 。
类、结构体或枚举类型的元类型是相应的类型名紧跟`.Type` 。协议类型的元类型——并不是运行时遵循 该协议的具体类型——是该协议名字紧跟`.Protocol` 。比如,类`SomeClass` 的元类型就是`SomeClass.Type` ,协议`SomeProtocol` 的元类型就是`SomeProtocal.Protocol` 。
类、结构体或枚举类型的元类型是相应的类型名紧跟 `.Type` 。协议类型的元类型——并不是运行时符合 该协议的具体类型——而 是该协议名字紧跟 `.Protocol` 。比如,类 `SomeClass` 的元类型就是 `SomeClass.Type` ,协议 `SomeProtocol` 的元类型就是 `SomeProtocal.Protocol` 。
你可以使用后缀`self` 表达式来获取类型。比如,`SomeClass.self` 返回`SomeClass` 本身,而不是`SomeClass` 的一个实例。同样,`SomeProtocol.self` 返回`SomeProtocol` 本身,而不是运行时遵循 `SomeProtocol` 的某个类型的实例。还可以对类型的实例使用`dynamicType` 表达式来获取该实例在运行阶段的类型,如下所示:
你可以使用后缀 `self` 表达式来获取类型。比如,`SomeClass.self` 返回 `SomeClass` 本身,而不是 `SomeClass` 的一个实例。同样,`SomeProtocol.self` 返回 `SomeProtocol` 本身,而不是运行时符合 `SomeProtocol` 的某个类型的实例。还可以对类型的实例使用 `dynamicType` 表达式来获取该实例在运行阶段的类型,如下所示:
```swift
class SomeBaseClass {
@ -255,26 +272,26 @@ class SomeSubClass: SomeBaseClass {
}
}
let someInstance : SomeBaseClass = SomeSubClass ()
// someInstance is of type SomeBaseClass at compile time, but
// someInstance is of type SomeSubClass at runtime
// someInstance 在编译期是 SomeBaseClass 类型,
// 但是在运行期则是 SomeSubClass 类型
someInstance . dynamicType . printClassName ()
// prints " SomeSubClass
// 打印 “ SomeSubClass”
```
可以使用恒等运算符(`===` 和 `!==` )来测试一个实例的运行时类型和它的编译时类型是否一致。
可以使用恒等运算符(`===` 和 `!==` )来测试一个实例的运行时类型和它的编译时类型是否一致。
```
if someInstance. dynamicType === someInstance.self {
```swift
if someInstance. dynamicType === SomeBaseClass . self {
print ( "The dynamic type of someInstance is SomeBaseCass" )
} else {
print ( "The dynamic type of someInstance isn't SomeBaseClass" )
}
// prints " The dynamic type of someInstance isn't SomeBaseClass"
// 打印 “ The dynamic type of someInstance isn't SomeBaseClass”
```
可以使用初始化表达式从某个类型的元类型构造出一个该类型的实例。对于类实例,必须使用 `required` 关键字标记被调用的构造器 ,或者使用 `final` 关键字标记整个类 。
可以使用初始化表达式从某个类型的元类型构造出一个该类型的实例。对于类实例,被调用的构造器 必须使用 `required` 关键字标记,或者整个类 使用 `final` 关键字标记。
```
```swift
class AnotherSubClass : SomeBaseClass {
let string : String
required init ( string : String ) {
@ -288,39 +305,42 @@ let metatype: AnotherSubClass.Type = AnotherSubClass.self
let anotherInstance = metatype . init ( string : "some string" )
```
> 元(Metatype) 类型语法
> *元类型* → [*类型*](../chapter3/03_Types.html #type) **.** **Type** | [*类型*](../chapter3/03_Types.html #type) **.** **Protocol**
> 元类型语法
> *元类型* → [*类型*](#type) **.** **Type** | [*类型*](#type) **.** **Protocol**
< a name = "type_inheritance_clause" ></ a >
##类型继承子句
## 类型继承子句
类型继承子句被用来指定一个命名型类型继承的 哪个类、遵循的 哪些协议。类型继承子句也用来指定一个类需要遵循的 协议。类型继承子句开始于冒号`:` ,其后是类所需遵循的协议或者类型标识符列表或者两者均有 。
类型继承子句被用来指定一个命名型类型继承自 哪个类、采纳 哪些协议。类型继承子句也用来指定一个类类型专属 协议。类型继承子句开始于冒号 `:` ,其后是类的超类或者一系列类型标识符 。
类可以继承单个超类,遵循 任意数量的协议。当定义一个类时,超类的名字必须出现在类型标识符列表首位,然后跟上该类需要遵循 的任意数量的协议。如果一个类不是从其它类继承而来,那么列表可以以协议开头。关于类继承更多的讨论和例子,见章节 Inheritance。
类可以继承单个超类,采纳 任意数量的协议。当定义一个类时,超类的名字必须出现在类型标识符列表首位,然后跟上该类需要采纳 的任意数量的协议。如果一个类不是从其它类继承而来,那么列表可以以协议开头。关于类继承更多的讨论和例子,请参阅 [继承 ](../chapter2/13_ Inheritance.html ) 。
其它命名型类型可能只继承或遵循一个协议列表 。协议类型可能 继承于其它 任意数量的协议。当一个协议类型继承于 其它协议时,其它协议的条件集合 会被整合在一起,然后其它 从当前协议继承的任意类型必须遵循 所有这些条件。正如在协议声明中所讨论的那样,可以把类的关键字放到 类型继承子句中 的首位,这样就可以用 一个类的条件来标记一个协议声明 。
其它命名型类型可能只继承或采纳一系列协议 。协议类型可以 继承自 任意数量的其他 协议。当一个协议类型继承自 其它协议时,其它协议中定义的要求 会被整合在一起,然后从当前协议继承的任意类型必须符合 所有这些条件。正如在 [ 协议声明 ](05_Declarations.html#protocol_declaration ) 中所讨论的那样,可以把 `class` 关键字放到协议类型的 类型继承子句的首位,这样就可以声明 一个类类型专属协议 。
枚举定义中的类型继承子句可以是一个协议列表,或是指定原始值的枚举——一个单独的指定 原始值类型的命名型类型。使用类型继承子句来指定原始值类型的枚举定义的例子, 见章节Raw V alues。
枚举定义中的类型继承子句可以是一系列协议,或是枚举的 原始值类型的命名型类型。在枚举定义中 使用类型继承子句来指定原始值类型的例子,请参阅 [原始值 ](../chapter2/08_Enumerations.html#raw_v alues ) 。
> 类型继承子句语法
> *类型继承子句* → **:** [*类需求*](../chapter3/03_Types.html#class_requirement) **,** [*类型继承列表*](../chapter3/03_Types.html#type_inheritance_list)
> *类型继承子句* → **:** [*类需 求*](../chapter3/03_Types.html#class_requirement)
> *类型继承子句* → **:** [*类型继承列表*](../chapter3/03_Types.html#type_inheritance_list)
> *类型继承列表 * → [*类型标识*](../chapter3/03_Types.html#type_identifier) | [*类型标识*](../chapter3/03_Types.html#type_identifier) **,** [*类型继承列表*](../chapter3/03_Types.html #type_inheritance_list)
> *类需求* → **类**
< a name = "type_inheritance_clause" ></ a >
> *类型继承子句* → **:** [*类要 求*](#class_requirement) **,** [*类型继承列表*](#type_inheritance_list)
> *类型继承子句* → **:** [*类要求*](#class_requirement)
> *类型继承子句 * → **:** [*类型继承列表*]( #type_inheritance_list)
< a name = "type_inheritance_list" ></ a >
> *类型继承列表* → [*类型标识符*](#type_identifier) | [*类型标识符*](#type_identifier) **,** [*类型继承列表*](#type_inheritance_list)
< a name = "class_requirement" ></ a >
> *类要求* → **class**
< a name = "type_inference" ></ a >
##类型推断
## 类型推断
Swift广泛的 使用类型推断,从而允许你可以忽 略代码中很多变量和表达式的类型或部分类型。比如,对于`var x: Int = 0` ,你可以完全忽 略类型而简写成`var x = 0` —— 编译器会正确的 推断出`x` 的类型`Int` 。类似的,当完整的类型可以从上下文推断出来时,你也可以忽 略类型的一部分。比如,如果你写了`let dict: Dictionary = ["A": 1]` ,编译提也 能推断出`dict` 的类型是`Dictionary<String, Int>` 。
Swift 广泛使用类型推断,从而允许你省 略代码中很多变量和表达式的类型或部分类型。比如,对于 `var x: Int = 0` ,你可以完全省 略类型而简写成 `var x = 0` , 编译器会正确推断出 `x` 的类型 `Int` 。类似的,当完整的类型可以从上下文推断出来时,你也可以省 略类型的一部分。比如,如果你写了 `let dict: Dictionary = ["A" : 1]` ,编译器 能推断出 `dict` 的类型是 `Dictionary<String, Int>` 。
在上面的两个例子中,类型信息从表达式树( expression tree) 的叶子节点传向根节点。也就是说,`var x: Int = 0` 中 `x` 的类型首先根据`0` 的类型进行推断,然后将该类型信息传递到根节点(变量`x` )。
在上面的两个例子中,类型信息从表达式树的叶子节点传向根节点。也就是说,`var x: Int = 0` 中 `x` 的类型首先根据 `0` 的类型进行推断,然后将该类型信息传递到根节点(变量 `x` )。
在Swift中, 类型信息也可以反方向流动——从根节点传向叶子节点。在下面的例子中, 常量`eFloat` 上的显式类型注解(`:Float` )导致数字字面量`2.71828` 的类型是`Float` 而非`Double` 。
在 Swift 中,类型信息也可以反方向流动——从根节点传向叶子节点。在下面的例子中,常量 `eFloat` 上的显式类型注解(`: Float` ) 将 导致数字字面量 `2.71828` 的类型是 `Float` 而非 `Double` 。
```swift
let e = 2.71828 // The type of e is inferred to be Double.
let eFloat : Float = 2.71828 // The type of eFloat is Float.
let e = 2.71828 // e 的类型会被推断为 Double
let eFloat : Float = 2.71828 // eFloat 的类型为 Float
```
Swift中的类型推断在单独的表达式或语句水平 上进行。这意味着所有用于推断 类型的信息必须可以从表达式或其某个子表达式的类型检查中获取。
Swift 中的类型推断在单独的表达式或语句上进行。这意味着所有用于类型推断 的信息必须可以从表达式或其某个子表达式的类型检查中获取到 。