Update 05_Declarations.md (#619)
This commit is contained in:
@ -6,23 +6,16 @@
|
||||
> 翻译:[marsprince](https://github.com/marsprince) [Lenhoon](https://github.com/marsprince)[(微博)](http://www.weibo.com/lenhoon)
|
||||
> 校对:[numbbbbb](https://github.com/numbbbbb), [stanzhai](https://github.com/stanzhai)
|
||||
|
||||
|
||||
|
||||
> 2.0
|
||||
> 翻译+校对:[Lenhoon](https://github.com/Lenhoon),
|
||||
> [BridgeQ](https://github.com/WXGBridgeQ)
|
||||
|
||||
|
||||
|
||||
> 2.1
|
||||
> 翻译:[mmoaay](https://github.com/mmoaay), [shanks](http://codebuild.me)
|
||||
> 校对:[shanks](http://codebuild.me)
|
||||
|
||||
|
||||
|
||||
> 2.2
|
||||
> 翻译:[星夜暮晨](https://github.com/SemperIdem)
|
||||
> 校对:
|
||||
|
||||
本页包含内容:
|
||||
|
||||
@ -33,7 +26,7 @@
|
||||
- [变量声明](#variable_declaration)
|
||||
- [存储型变量和存储型变量属性](#stored_variables_and_stored_variable_properties)
|
||||
- [计算型变量和计算型属性](#computed_variables_and_computed_properties)
|
||||
- [存储型变量观察器和属性观察器](#stored_variable_observers_and_property_observers)
|
||||
- [存储型变量和属性的观察器](#stored_variable_observers_and_property_observers)
|
||||
- [类型变量属性](#type_variable_properties)
|
||||
- [类型别名声明](#type_alias_declaration)
|
||||
- [函数声明](#function_declaration)
|
||||
@ -41,13 +34,12 @@
|
||||
- [输入输出参数](#in-out_parameters)
|
||||
- [特殊参数](#special_kinds_of_parameters)
|
||||
- [特殊方法](#special_kinds_of_methods)
|
||||
- [柯里化函数](#curried_functions)
|
||||
- [抛出错误的函数和方法](#throwing_functions_and_methods)
|
||||
- [重新抛出错误的函数和方法](#rethrowing_functions_and_methods)
|
||||
- [重抛错误的函数和方法](#rethrowing_functions_and_methods)
|
||||
- [枚举声明](#enumeration_declaration)
|
||||
- [包含任意类型用例的枚举](#enumerations_with_cases_of_any_type)
|
||||
- [任意类型的枚举用例](#enumerations_with_cases_of_any_type)
|
||||
- [递归枚举](#enumerations_with_indirection)
|
||||
- [包含原始值类型的枚举](#enumerations_with_cases_of_a_raw-value_type)
|
||||
- [拥有原始值的枚举用例](#enumerations_with_cases_of_a_raw-value_type)
|
||||
- [访问枚举用例](#accessing_enumeration_cases)
|
||||
- [结构体声明](#structure_declaration)
|
||||
- [类声明](#class_declaration)
|
||||
@ -66,9 +58,9 @@
|
||||
- [声明修饰符](#declaration_modifiers)
|
||||
- [访问控制级别](#access_control_levels)
|
||||
|
||||
*声明 (declaration)* 用以向程序里引入新的名字或者构造。举例来说,可以使用声明来引入函数和方法,变量和常量,或者来定义新的命名枚举,结构,类和协议类型。还可以使用声明来扩展一个已经存在的命名的类型的行为,或者在程序里引入在其它地方声明的符号。
|
||||
*声明 (declaration)* 用以向程序里引入新的名字或者结构。举例来说,可以使用声明来引入函数和方法,变量和常量,或者定义新的具有命名的枚举、结构、类和协议类型。还可以使用声明来扩展一个既有的具有命名的类型的行为,或者在程序里引入在其它地方声明的符号。
|
||||
|
||||
在 Swift 中,大多数声明在某种意义上讲也是定义,实现或初始化往往伴随着声明。这意味着,由于协议往往并不提供实现,大多数协议仅仅只是声明而已。为了方便起见,也因为这些区别在 Swift 中不是很重要,*“声明”*这个术语同时包含了声明和定义。
|
||||
在 Swift 中,大多数声明在某种意义上讲也是定义,因为声明往往伴随着实现或初始化。由于协议并不提供实现,大多数协议成员仅仅只是声明而已。为了方便起见,也是因为这些区别在 Swift 中并不是很重要,“声明”这个术语同时包含了声明和定义两种含义。
|
||||
|
||||
> 声明语法
|
||||
> <a name="declaration"></a>
|
||||
@ -92,7 +84,7 @@
|
||||
<a name="top-level_code"></a>
|
||||
## 顶级代码
|
||||
|
||||
Swift 的源文件中的顶级代码 (top-level code) 由零个或多个语句,声明和表达式组成。默认情况下,在一个源文件的顶层声明的变量,常量和其他命名的声明语句可以被同一模块中的每一个源文件中的代码访问。可以使用一个访问级别修饰符来标记声明,从而覆盖默认行为,请参阅 [访问控制级别](#access_control_levels)。
|
||||
Swift 的源文件中的顶级代码 (top-level code) 由零个或多个语句、声明和表达式组成。默认情况下,在一个源文件的顶层声明的变量,常量和其他具有命名的声明可以被同模块中的每一个源文件中的代码访问。可以使用一个访问级别修饰符来标记声明来覆盖这种默认行为,请参阅 [访问控制级别](#access_control_levels)。
|
||||
|
||||
> 顶级声明语法
|
||||
> *顶级声明* → [*多条语句*](10_Statements.md#statements)<sub>可选</sub>
|
||||
@ -104,11 +96,10 @@ Swift 的源文件中的顶级代码 (top-level code) 由零个或多个语句
|
||||
|
||||
```swift
|
||||
{
|
||||
<#语句#>
|
||||
语句
|
||||
}
|
||||
```
|
||||
|
||||
代码块中的*语句*包括声明,表达式和各种其他类型的语句,它们按照在源码中的出现顺序被依次执行。
|
||||
代码块中的“语句”包括声明、表达式和各种其他类型的语句,它们按照在源码中的出现顺序被依次执行。
|
||||
|
||||
> 代码块语法
|
||||
> <a name="code-block"></a>
|
||||
@ -117,17 +108,17 @@ Swift 的源文件中的顶级代码 (top-level code) 由零个或多个语句
|
||||
<a name="import_declaration"></a>
|
||||
## 导入声明
|
||||
|
||||
*导入声明 (import declaration)* 让你可以使用在其他文件中声明的内容。导入语句的基本形式是导入整个模块,它由 `import` 关键字开始,后面紧跟一个模块名:
|
||||
*导入声明 (import declaration)* 让你可以使用在其他文件中声明的内容。导入语句的基本形式是导入整个模块,它由 `import` 关键字和紧随其后的模块名组成:
|
||||
|
||||
```swift
|
||||
import <#模块#>
|
||||
import 模块
|
||||
```
|
||||
|
||||
可以对导入提供更细致的控制,如指定一个特殊的子模块或者指定一个模块或子模块中的某个声明。提供了这些限制后,在当前作用域中,只有导入的符号是可用的,而不是整个模块。
|
||||
可以对导入操作提供更细致的控制,如指定一个特殊的子模块或者指定一个模块或子模块中的某个声明。提供了这些限制后,在当前作用域中,只有被导入的符号是可用的,而不是整个模块中的所有声明。
|
||||
|
||||
```swift
|
||||
import <#导入类型#> <#模块#>.<#符号名#>
|
||||
import <#模块#>.<#子模块#>
|
||||
import 导入类型 模块.符号名
|
||||
import 模块.子模块
|
||||
```
|
||||
|
||||
<a name="grammer_of_an_import_declaration"></a>
|
||||
@ -144,23 +135,23 @@ import <#模块#>.<#子模块#>
|
||||
<a name="constant_declaration"></a>
|
||||
## 常量声明
|
||||
|
||||
*常量声明 (constant declaration)* 可以在程序中命名一个常量。常量以关键字 `let` 来声明,遵循如下的格式:
|
||||
*常量声明 (constant declaration)* 可以在程序中引入一个具有命名的常量。常量以关键字 `let` 来声明,遵循如下格式:
|
||||
|
||||
```swift
|
||||
let <#常量名称#>: <#类型#> = <#表达式#>
|
||||
let 常量名称: 类型 = 表达式
|
||||
```
|
||||
|
||||
常量声明在*常量名称*和初始化*表达式*的值之间,定义了一种不可变的绑定关系;当常量的值被设定之后,它就无法被更改。这意味着,如果常量以类对象来初始化,对象本身的内容是可以改变的,但是常量和该对象之间的结合关系是不能改变的。
|
||||
常量声明在“常量名称”和用于初始化的“表达式”的值之间定义了一种不可变的绑定关系;当常量的值被设定之后,它就无法被更改。这意味着,如果常量以类对象来初始化,对象本身的内容是可以改变的,但是常量和该对象之间的绑定关系是不能改变的。
|
||||
|
||||
当一个常量被声明为全局变量,它必须被给定一个初始值。在类或者结构体中声明一个常量时,它被认为是一个*常量属性 (constant property)*。常量声明不能是计算型属性,因此也没有存取方法。
|
||||
当一个常量被声明为全局常量时,它必须拥有一个初始值。在类或者结构中声明一个常量时,它将作为*常量属性 (constant property)*。常量声明不能是计算型属性,因此也没有存取方法。
|
||||
|
||||
如果常量名称是元组形式,元组中的每一项的名称会和对应的初始化表达式的值绑定。
|
||||
如果常量名称是元组形式,元组中每一项的名称都会和初始化表达式中对应的值进行绑定。
|
||||
|
||||
```swift
|
||||
let (firstNumber, secondNumber) = (10, 42)
|
||||
```
|
||||
|
||||
在上例中,`firstNumber` 是一个值为 `10` 的常量,`secnodeName` 是一个值为 `42` 的常量。所有常量都可以独立的使用:
|
||||
在上例中,`firstNumber` 是一个值为 `10` 的常量,`secnodeName` 是一个值为 `42` 的常量。所有常量都可以独立地使用:
|
||||
|
||||
```swift
|
||||
print("The first number is \(firstNumber).")
|
||||
@ -169,7 +160,7 @@ print("The second number is \(secondNumber).")
|
||||
// 打印 “The second number is 42.”
|
||||
```
|
||||
|
||||
当常量名称的类型 (`:` *type*) 可以被推断出时,类型标注在常量声明中是一个可选项,正如 [类型推断](03_Types.md#type_inference) 中所描述的。
|
||||
当常量名称的类型 (`:` 类型) 可以被推断出时,类型标注在常量声明中是可选的,正如 [类型推断](03_Types.md#type_inference) 中所描述的。
|
||||
|
||||
声明一个常量类型属性要使用 `static` 声明修饰符。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties)中有介绍。
|
||||
|
||||
@ -189,14 +180,14 @@ print("The second number is \(secondNumber).")
|
||||
<a name="variable_declaration"></a>
|
||||
## 变量声明
|
||||
|
||||
*变量声明 (variable declaration)* 可以在程序中声明一个变量,它以关键字 `var` 来声明。
|
||||
*变量声明 (variable declaration)* 可以在程序中引入一个具有命名的变量,它以关键字 `var` 来声明。
|
||||
|
||||
变量声明有几种不同的形式,可以声明不同种类的命名值和可变值,如存储型和计算型变量和属性,属性观察器,以及静态变量属性。所使用的声明形式取决于变量声明的适用范围和打算声明的变量类型。
|
||||
|
||||
> 注意
|
||||
> 也可以在协议声明的上下文中声明属性,详情请参阅 [协议属性声明](#protocol_property_declaration)。
|
||||
> 也可以在协议声明中声明属性,详情请参阅 [协议属性声明](#protocol_property_declaration)。
|
||||
|
||||
可以在子类中使用 `override` 声明修饰符来标记继承来的属性的声明,从而重写属性,详情请参阅 [重写](../chapter2/13_Inheritance.md#overriding)。
|
||||
可以在子类中重写继承来的变量属性,使用 `override` 声明修饰符标记属性的声明即可,详情请参阅 [重写](../chapter2/13_Inheritance.md#overriding)。
|
||||
|
||||
<a name="stored_variables_and_stored_variable_properties"></a>
|
||||
### 存储型变量和存储型变量属性
|
||||
@ -204,16 +195,16 @@ print("The second number is \(secondNumber).")
|
||||
使用如下形式声明一个存储型变量或存储型变量属性:
|
||||
|
||||
```swift
|
||||
var <#变量名称#>: <#类型#> = <#表达式#>
|
||||
var 变量名称: 类型 = 表达式
|
||||
```
|
||||
|
||||
可以在全局范围,函数内部,或者在类和结构体的声明中使用这种形式来声明一个变量。当变量以这种形式在全局范围或者函数内部被声明时,它代表一个存储型变量。当它在类或者结构体中被声明时,它代表一个*存储型变量属性 (stored variable property)*。
|
||||
可以在全局范围,函数内部,或者在类和结构的声明中使用这种形式来声明一个变量。当变量以这种形式在全局范围或者函数内部被声明时,它代表一个存储型变量。当它在类或者结构中被声明时,它代表一个*存储型变量属性 (stored variable property)*。
|
||||
|
||||
用于初始化的表达式不可以在协议的声明中出现,在其他情况下,该表达式是可选的。如果没有初始化表达式,那么变量声明必须包含类型标注 (`:` *type*)。
|
||||
|
||||
对于常量的声明,如果变量名称是一个元组,元组中每一项的名称都要和初始化表达式中的相应值绑定。
|
||||
如同常量声明,如果变量名称是元组形式,元组中每一项的名称都会和初始化表达式中对应的值进行绑定。
|
||||
|
||||
正如名字一样,存储型变量和存储型变量属性的值会存储在内存中。
|
||||
正如名字所示,存储型变量和存储型变量属性的值会存储在内存中。
|
||||
|
||||
<a name="computed_variables_and_computed_properties"></a>
|
||||
### 计算型变量和计算型属性
|
||||
@ -221,50 +212,50 @@ var <#变量名称#>: <#类型#> = <#表达式#>
|
||||
使用如下形式声明一个计算型变量或计算型属性:
|
||||
|
||||
```swift
|
||||
var <#变量名称#>: <#类型#> {
|
||||
var 变量名称: 类型 {
|
||||
get {
|
||||
<#语句#>
|
||||
语句
|
||||
}
|
||||
set(<#setter 名称#>) {
|
||||
<#语句#>
|
||||
set(setter 名称) {
|
||||
语句
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
可以在全局范围,函数内部,以及类,结构体,枚举,扩展声明的上下文中使用这种形式的声明。当变量以这种形式在全局范围或者函数内部被声明时,它代表一个计算型变量。当它在类,结构体,枚举,扩展声明的上下文中被声明时,它代表一个*计算型属性 (computed property)*。
|
||||
可以在全局范围、函数内部,以及类、结构、枚举、扩展的声明中使用这种形式的声明。当变量以这种形式在全局范围或者函数内部被声明时,它表示一个计算型变量。当它在类、结构、枚举、扩展声明的上下文中被声明时,它表示一个*计算型属性 (computed property)*。
|
||||
|
||||
getter 用来读取变量值,setter 用来写入变量值。setter 子句是可选的,getter 子句是必须的。也可以将这些子句都省略,直接返回请求的值,正如在 [只读计算型属性](../chapter2/10_Properties.md#computed_properties) 中描述的那样。但是如果提供了一个 setter 子句,也必须提供一个 getter 子句。
|
||||
getter 用来读取变量值,setter 用来写入变量值。setter 子句是可选的,getter 子句是必须的。不过也可以将这些子句都省略,直接返回请求的值,正如在 [只读计算型属性](../chapter2/10_Properties.md#computed_properties) 中描述的那样。但是如果提供了一个 setter 子句,就必须也提供一个 getter 子句。
|
||||
|
||||
圆括号内的 setter 的名称是可选的。如果提供了一个 setter 名称,它就会作为 setter 的参数名称使用。如果不提供 setter 名称,setter 的参数的默认名称为 `newValue`,正如在 [便捷 setter 声明](../chapter2/10_Properties.md#shorthand_setter_declaration) 中描述的那样。
|
||||
setter 的圆括号以及 setter 名称是可选的。如果提供了 setter 名称,它就会作为 setter 的参数名称使用。如果不提供 setter 名称,setter 的参数的默认名称为 `newValue`,正如在 [便捷 setter 声明](../chapter2/10_Properties.md#shorthand_setter_declaration) 中描述的那样。
|
||||
|
||||
与存储型变量和存储型属性不同,计算型变量和计算型属性的值不存储在内存中。
|
||||
|
||||
要获得更多关于计算型属性的信息和例子,请参阅 [计算型属性](../chapter2/10_Properties.md#computed_properties)。
|
||||
|
||||
<a name="stored_variable_observers_and_property_observers"></a>
|
||||
### 存储型变量观察器和属性观察器
|
||||
### 存储型变量和属性的观察器
|
||||
|
||||
可以在声明存储型变量或属性时提供 `willSet` 和 `didSet` 观察器。一个包含观察器的存储型变量或属性以如下形式声明:
|
||||
|
||||
```swift
|
||||
var <#变量名称#>: <#类型#> = <#表达式#> {
|
||||
willSet(<#setter 名称#>) {
|
||||
<#语句#>
|
||||
var 变量名称: 类型 = 表达式 {
|
||||
willSet(setter 名称) {
|
||||
语句
|
||||
}
|
||||
didSet(<#setter 名称#>) {
|
||||
<#语句#>
|
||||
didSet(setter 名称) {
|
||||
语句
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
可以在全局范围,函数内部,或者类,结构体声明的上下文中使用这种形式的声明。当变量以这种形式在全局范围或者函数内部被声明时,观察器代表一个存储型变量观察器。当它在类,结构体声明的上下文中被声明时,观察器代表一个属性观察器。
|
||||
可以在全局范围、函数内部,或者类、结构的声明中使用这种形式的声明。当变量以这种形式在全局范围或者函数内部被声明时,观察器表示一个存储型变量观察器。当它在类和结构的声明中被声明时,观察器表示一个属性观察器。
|
||||
|
||||
可以为任何存储型属性添加观察器。也可以通过重写父类属性的方式为任何继承的属性(无论是存储型还是计算型的)添加观察器
|
||||
,正如 [重写属性观察器](../chapter2/13_Inheritance.md#overriding_property_observers) 中所描述的。
|
||||
|
||||
用于初始化的表达式在一个类或者结构体的声明中是可选的,但是在其他地方是必须的。如果类型可以从初始化表达式中推断而来,那么这个类型标注是可选的。
|
||||
用于初始化的表达式在类或者结构的声明中是可选的,但是在其他声明中则是必须的。如果可以从初始化表达式中推断出类型信息,那么可以不提供类型标注。
|
||||
|
||||
当变量或属性的值被改变时,`willSet` 和 `didSet` 观察器提供了一种观察方法。观察器不会在变量或属性第一次初始化时被调用,它们仅当值在初始化环境之外被改变时才会被调用。
|
||||
当变量或属性的值被改变时,`willSet` 和 `didSet` 观察器提供了一种观察方法。观察器会在变量的值被改变时调用,但不会在初始化时被调用。
|
||||
|
||||
`willSet` 观察器只在变量或属性的值被改变之前调用。新的值作为一个常量传入 `willSet` 观察器,因此不可以在 `willSet` 中改变它。`didSet` 观察器在变量或属性的值被改变后立即调用。和 `willSet` 观察器相反,为了方便获取旧值,旧值会传入 `didSet` 观察器。这意味着,如果在变量或属性的 `didiset` 观察器中设置值,设置的新值会取代刚刚在 `willSet` 观察器中传入的那个值。
|
||||
|
||||
@ -328,13 +319,13 @@ var <#变量名称#>: <#类型#> = <#表达式#> {
|
||||
<a name="type_alias_declaration"></a>
|
||||
## 类型别名声明
|
||||
|
||||
*类型别名 (type alias)* 声明可以在程序中为一个现存类型声明一个别名。类型别名声明语句使用关键字 `typealias` 声明,遵循如下的形式:
|
||||
*类型别名 (type alias)* 声明可以在程序中为一个既有类型声明一个别名。类型别名声明语句使用关键字 `typealias` 声明,遵循如下的形式:
|
||||
|
||||
```swift
|
||||
typealias <#类型别名#> = <#现存类型#>
|
||||
typealias 类型别名 = 现存类型
|
||||
```
|
||||
|
||||
当声明一个类型的别名后,可以在程序的任何地方使用*别名*来代替*现存类型*。*现存类型*可以是命名类型或者混合类型。类型别名不产生新的类型,它只是可以使用别名来引用现存类型。
|
||||
当声明一个类型的别名后,可以在程序的任何地方使用“别名”来代替现有类型。现有类型可以是具有命名的类型或者混合类型。类型别名不产生新的类型,它只是使用别名来引用现有类型。
|
||||
|
||||
另请参阅 [协议关联类型声明](#protocol_associated_type_declaration)。
|
||||
|
||||
@ -352,23 +343,23 @@ typealias <#类型别名#> = <#现存类型#>
|
||||
<a name="function_declaration"></a>
|
||||
## 函数声明
|
||||
|
||||
使用*函数声明 (function declaration)* 在程序中引入新的函数或者方法。当一个函数被声明在类,结构体,枚举,或者协议的上下文中,会作为一个方法。函数声明使用关键字 `func`,遵循如下的形式:
|
||||
使用*函数声明 (function declaration)* 在程序中引入新的函数或者方法。在类、结构体、枚举,或者协议中声明的函数会作为方法。函数声明使用关键字 `func`,遵循如下的形式:
|
||||
|
||||
```swift
|
||||
func <#函数名称#>(<#参数列表#>) -> <#返回类型#> {
|
||||
<#语句#>
|
||||
func 函数名称(参数列表) -> 返回类型 {
|
||||
语句
|
||||
}
|
||||
```
|
||||
|
||||
如果函数返回 `Void` 类型,返回类型可以省略,如下所示:
|
||||
|
||||
```swift
|
||||
func <#函数名称#>(<#参数列表#>) {
|
||||
<#语句#>
|
||||
func 函数名称(参数列表) {
|
||||
语句
|
||||
}
|
||||
```
|
||||
|
||||
每个参数的类型都要标明,它们不能被推断出来。虽然函数的参数默认是常量,也可以在参数名前添加 `let` 来强调这一行为。如果您在某个参数名前面加上了 `inout`,那么这个参数就可以在这个函数作用域当中被修改。更多关于 `inout` 参数的讨论,请参阅 [输入输出参数](#in-out_parameters)。
|
||||
每个参数的类型都要标明,因为它们不能被推断出来。虽然函数的参数默认是常量,也可以在参数名前添加 `let` 来强调这一行为。如果您在某个参数名前面加上了 `inout`,那么这个参数就可以在这个函数作用域当中被修改。更多关于 `inout` 参数的讨论,请参阅 [输入输出参数](#in-out_parameters)。
|
||||
|
||||
函数可以使用元组类型作为返回类型来返回多个值。
|
||||
|
||||
@ -379,11 +370,9 @@ func <#函数名称#>(<#参数列表#>) {
|
||||
|
||||
函数的参数列表由一个或多个函数参数组成,参数间以逗号分隔。函数调用时的参数顺序必须和函数声明时的参数顺序一致。最简单的参数列表有着如下的形式:
|
||||
|
||||
```swift
|
||||
<#参数名称#>: <#参数类型#>
|
||||
```
|
||||
`参数名称`: `参数类型`
|
||||
|
||||
一个参数有一个内部名称,这个内部名称可以在函数体内被使用。同样也可以作为外部名称,当调用函数时这个外部名称被作为实参的标签来使用。默认情况下,第一个参数的外部名称省略不写,第二个和之后的参数使用它们的内部名称作为它们的外部名称。例如:
|
||||
一个参数有一个内部名称,这个内部名称可以在函数体内被使用。还有一个外部名称,当调用函数时这个外部名称被作为实参的标签来使用。默认情况下,第一个参数的外部名称会被省略,第二个和之后的参数使用它们的内部名称作为它们的外部名称。例如:
|
||||
|
||||
```swift
|
||||
func f(x: Int, y: Int) -> Int { return x + y }
|
||||
@ -392,14 +381,12 @@ f(1, y: 2) // 参数 y 有标签,参数 x 则没有
|
||||
|
||||
可以按照如下两种形式之一,重写参数名称的默认行为:
|
||||
|
||||
```swift
|
||||
<#外部参数名称#> <#内部参数名称#>: <#参数类型#>
|
||||
_ <#内部参数名称#>: <#参数类型#>
|
||||
```
|
||||
`外部参数名称` `内部参数名称`: `参数类型`
|
||||
_ `内部参数名称`: `参数类型`
|
||||
|
||||
在内部参数名称前的名称赋予这个参数一个外部名称,这个名称可以和内部参数的名称不同。外部参数名称在函数被调用时必须被使用。对应的参数在方法或函数被调用时必须有外部名。
|
||||
在内部参数名称前的名称会作为这个参数的外部名称,这个名称可以和内部参数的名称不同。外部参数名称在函数被调用时必须被使用,即对应的参数在方法或函数被调用时必须有外部名。
|
||||
|
||||
内部参数名称前的下划线(`_`)使该参数在函数被调用时没有名称。在函数或方法调用时,对应的参数必须没有名字。
|
||||
内部参数名称前的下划线(`_`)可使该参数在函数被调用时没有名称。在函数或方法调用时,对应的参数必须没有名字。
|
||||
|
||||
```swift
|
||||
func f(x x: Int, withY y: Int, _ z: Int) -> Int { return x + y + z }
|
||||
@ -417,11 +404,11 @@ f(x: 1, withY: 2, 3) // 参数 x 和 y 是有标签的,参数 z 则没有
|
||||
|
||||
这种行为被称为*拷入拷出 (copy-in copy-out)* 或*值结果调用 (call by value result)*。例如,当一个计算型属性或者一个具有属性观察器的属性被用作函数的输入输出参数时,其 getter 会在函数调用时被调用,而其 setter 会在函数返回时被调用。
|
||||
|
||||
作为一种优化手段,当参数值存储在内存中的物理地址时,在函数体内部和外部均会使用同一内存位置。这种优化行为被称为*引用调用 (call by reference)*,它满足了拷入拷出模型的所有需求,而消除了复制带来的开销。不要依赖于拷入拷出与引用调用之间的行为差异。
|
||||
作为一种优化手段,当参数值存储在内存中的物理地址时,在函数体内部和外部均会使用同一内存位置。这种优化行为被称为*引用调用 (call by reference)*,它满足了拷入拷出模式的所有要求,且消除了复制带来的开销。在代码中,要规范使用拷入拷出模式,不要依赖于引用调用。
|
||||
|
||||
不要使用传递给输入输出参数的值,即使原始值在当前作用域中依然可用。当函数返回时,你对原始值所做的更改会被拷贝的值所覆盖。不要依赖于引用调用的优化机制来试图阻止这种覆盖。
|
||||
不要使用传递给输入输出参数的值,即使原始值在当前作用域中依然可用。当函数返回时,你对原始值所做的更改会被拷贝的值所覆盖。不要依赖于引用调用的优化机制来试图避免这种覆盖。
|
||||
|
||||
你不能将同一个值传递给多个输入输出参数,因为多个输入输出参数引发的拷贝与覆盖行为的顺序是不确定的,因此原始值的最终值也将无法确定。例如:
|
||||
不能将同一个值传递给多个输入输出参数,因为这种情况下的拷贝与覆盖行为的顺序是不确定的,因此原始值的最终值也将无法确定。例如:
|
||||
|
||||
```swift
|
||||
var x = 10
|
||||
@ -456,17 +443,17 @@ print(x)
|
||||
<a name="special_kinds_of_parameters"></a>
|
||||
### 特殊参数
|
||||
|
||||
参数可以被忽略,参数的数量可变,并且还可以提供默认值,使用形式如下:
|
||||
参数可以被忽略,数量可以不固定,还可以为其提供默认值,使用形式如下:
|
||||
|
||||
```swift
|
||||
_ : <#参数类型#>
|
||||
<#参数名称#>: <#参数类型#>...
|
||||
<#参数名称#.: <#参数类型#> = <#默认参数值#>
|
||||
_ : 参数类型
|
||||
参数名称: 参数类型...
|
||||
参数名称: 参数类型 = 默认参数值
|
||||
```
|
||||
|
||||
以下划线(`_`)命名的参数是被显式忽略的,无法在函数体内使用。
|
||||
以下划线(`_`)命名的参数会被显式忽略,无法在函数体内使用。
|
||||
|
||||
一个参数的基础类型名称如果紧跟着三个点(`...`),会被视为可变参数。一个函数至多可以拥有一个可变参数,且必须是最后一个参数。可变参数会作为该参数类型的数组。举例来讲,可变参数 `Int...` 被看作 `[Int]`。关于使用可变参数的例子,请参阅 [可变参数](../chapter2/06_Functions.md#variadic_parameters)。
|
||||
一个参数的基本类型名称如果紧跟着三个点(`...`),会被视为可变参数。一个函数至多可以拥有一个可变参数,且必须是最后一个参数。可变参数会作为包含该参数类型元素的数组处理。举例来讲,可变参数 `Int...` 会作为 `[Int]` 来处理。关于使用可变参数的例子,请参阅 [可变参数](../chapter2/06_Functions.md#variadic_parameters)。
|
||||
|
||||
如果在参数类型后面有一个以等号(`=`)连接的表达式,该参数会拥有默认值,即给定表达式的值。当函数被调用时,给定的表达式会被求值。如果参数在函数调用时被省略了,就会使用其默认值。
|
||||
|
||||
@ -480,11 +467,11 @@ f(x: 7) // 无效,该参数没有外部名称
|
||||
<a name="special_kinds_of_methods"></a>
|
||||
### 特殊方法
|
||||
|
||||
枚举或结构体的方法如果会修改 `self` 属性,必须以 `mutating` 声明修饰符标记。
|
||||
枚举或结构体的方法如果会修改 `self`,则必须以 `mutating` 声明修饰符标记。
|
||||
|
||||
子类重写超类中的方法必须以 `override` 声明修饰符标记。重写方法时不使用 `override` 修饰符,或者使用了 `override` 修饰符却并没有重写超类方法,都会产生一个编译时错误。
|
||||
子类重写超类中的方法必须以 `override` 声明修饰符标记。重写方法时不使用 `override` 修饰符,或者被 `override` 修饰符修饰的方法并未对超类方法构成重写,都会导致编译错误。
|
||||
|
||||
枚举或者结构体中的类型方法,要以 `static` 声明修饰符标记,而对于类中的类型方法,除了使用 `static`,也可使用 `class` 声明修饰符标记。
|
||||
枚举或者结构体中的类型方法,要以 `static` 声明修饰符标记,而对于类中的类型方法,除了使用 `static`,还可使用 `class` 声明修饰符标记。
|
||||
|
||||
<a name="throwing_functions_and_methods"></a>
|
||||
### 抛出错误的函数和方法
|
||||
@ -492,21 +479,21 @@ f(x: 7) // 无效,该参数没有外部名称
|
||||
可以抛出错误的函数或方法必须使用 `throws` 关键字标记。这类函数和方法被称为抛出函数和抛出方法。它们有着下面的形式:
|
||||
|
||||
```swift
|
||||
func <#函数名称#>(<#参数列表#>) throws -> <#返回类型#> {
|
||||
<#语句#>
|
||||
func 函数名称(参数列表) throws -> 返回类型 {
|
||||
语句
|
||||
}
|
||||
```
|
||||
|
||||
抛出函数或抛出方法的调用必须包裹在 `try` 或者 `try!` 表达式中(也就是说,在作用域内使用 `try` 或者 `try!` 运算符)。
|
||||
|
||||
`throws` 关键字是函数的类型的一部分,非抛出函数是抛出函数的子类型。所以,可以在使用抛出函数的地方使用非抛出函数。对于柯里化函数,`throws` 关键字仅应用于最内层的函数。
|
||||
`throws` 关键字是函数的类型的一部分,非抛出函数是抛出函数的子类型。所以,可以在使用抛出函数的地方使用非抛出函数。
|
||||
|
||||
不能仅基于函数能否抛出错误来进行函数重载。也就是说,可以基于函数的函数类型的参数能否抛出错误来进行函数重载。
|
||||
|
||||
抛出方法不能重写非抛出方法,而且抛出方法不能满足协议对于非抛出方法的要求。也就是说,非抛出方法可以重写抛出方法,而且非抛出方法可以满足协议对于抛出方法的要求。
|
||||
|
||||
<a name="rethrowing_functions_and_methods"></a>
|
||||
### 重新抛出错误的函数和方法
|
||||
### 重抛错误的函数和方法
|
||||
|
||||
函数或方法可以使用 `rethrows` 关键字来声明,从而表明仅当该函数或方法的一个函数类型的参数抛出错误时,该函数或方法才抛出错误。这类函数和方法被称为重抛函数和重抛方法。重新抛出错误的函数或方法必须至少有一个参数的类型为抛出函数。
|
||||
|
||||
@ -516,7 +503,7 @@ func functionWithCallback(callback: () throws -> Int) rethrows {
|
||||
}
|
||||
```
|
||||
|
||||
重抛函数或者方法不能够从它本身直接抛出任何错误,这意味着它不能够包含 `throw` 语句。它只能够传递作为参数的抛出函数所抛出的错误。例如,在 `do-catch` 代码块中调用抛出函数,以及在 `catch` 闭包中处理另一种抛出的错误错误都是不允许的。
|
||||
重抛函数或者方法不能够从自身直接抛出任何错误,这意味着它不能够包含 `throw` 语句。它只能够传递作为参数的抛出函数所抛出的错误。例如,在 `do-catch` 代码块中调用抛出函数,并在 `catch` 子句中抛出其它错误都是不允许的。
|
||||
|
||||
抛出方法不能重写重抛方法,而且抛出方法不能满足协议对于重抛方法的要求。也就是说,重抛方法可以重写抛出方法,而且重抛方法可以满足协议对于抛出方法的要求。
|
||||
|
||||
@ -561,33 +548,33 @@ func functionWithCallback(callback: () throws -> Int) rethrows {
|
||||
|
||||
在程序中使用*枚举声明 (enumeration declaration)* 来引入一个枚举类型。
|
||||
|
||||
枚举声明有两种基本形式,使用关键字 `enum` 来声明。枚举声明体包含零个或多个值,称为枚举用例,还可包含任意数量的声明,包括计算型属性,实例方法,类型方法,构造器,类型别名,甚至其他枚举,结构体,和类。枚举声明不能包含析构器或者协议声明。
|
||||
枚举声明有两种基本形式,使用关键字 `enum` 来声明。枚举声明体包含零个或多个值,称为枚举用例,还可包含任意数量的声明,包括计算型属性、实例方法、类型方法、构造器、类型别名,甚至其他枚举、结构体和类。枚举声明不能包含析构器或者协议声明。
|
||||
|
||||
枚举类型可以采纳任意数量的协议,但是枚举不能从类,结构体和其他枚举继承。
|
||||
枚举类型可以采纳任意数量的协议,但是枚举不能从类、结构体和其他枚举继承。
|
||||
|
||||
不同于类或者结构体,枚举类型并不提供隐式的默认构造器,所有构造器必须显式声明。一个构造器可以委托给枚举中的其他构造器,但是构造过程仅当构造器将一个枚举用例指定给 `self` 后才算完成。
|
||||
不同于类或者结构体,枚举类型并不隐式提供默认构造器,所有构造器必须显式声明。一个构造器可以委托给枚举中的其他构造器,但是构造过程仅当构造器将一个枚举用例赋值给 `self` 后才算完成。
|
||||
|
||||
和结构体类似但是和类不同,枚举是值类型。枚举实例在被赋值到变量或常量时,或者传递给函数作为参数时会被复制。更多关于值类型的信息,请参阅 [结构体和枚举是值类型](../chapter2/09_Classes_and_Structures.md#structures_and_enumerations_are_value_types)。
|
||||
|
||||
可以扩展枚举类型,正如在 [扩展声明](#extension_declaration) 中讨论的一样。
|
||||
|
||||
<a name="enumerations_with_cases_of_any_type"></a>
|
||||
### 包含任意类型用例的枚举
|
||||
### 任意类型的枚举用例
|
||||
|
||||
如下的形式声明了一个包含任意类型枚举用例的枚举变量:
|
||||
|
||||
```swift
|
||||
enum <#枚举名称#>: <#采纳的协议#> {
|
||||
case <#枚举用例1#>
|
||||
case <#枚举用例2#>(<#关联值类型#>)
|
||||
}
|
||||
enum 枚举名称: 采纳的协议 {
|
||||
case 枚举用例1
|
||||
case 枚举用例2(关联值类型)
|
||||
}
|
||||
```
|
||||
|
||||
这种形式的枚举声明在其他语言中有时被叫做可识别联合。
|
||||
|
||||
在这种形式中,每个用例块由关键字 `case` 开始,后面紧接一个或多个以逗号分隔的枚举用例。每个用例名必须是独一无二的。每个用例也可以指定它所存储的指定类型的值,这些类型在关联值类型的元组中被指定,紧跟用例名之后。
|
||||
|
||||
具有关联值的枚举用例可以像函数一样使用,从而通过指定的关联值创建一个枚举实例。和真正的函数一样,你可以获取一个枚举用例的引用,然后在后续代码中调用它。
|
||||
具有关联值的枚举用例可以像函数一样使用,通过指定的关联值创建枚举实例。和真正的函数一样,你可以获取枚举用例的引用,然后在后续代码中调用它。
|
||||
|
||||
```swift
|
||||
enum Number {
|
||||
@ -605,9 +592,9 @@ let evenInts: [Number] = [0, 2, 4, 6].map(f)
|
||||
要获得更多关于具有关联值的枚举用例的信息和例子,请参阅 [关联值](../chapter2/08_Enumerations.md#associated_values)。
|
||||
|
||||
<a name="enumerations_with_indirection"></a>
|
||||
### 递归枚举
|
||||
#### 递归枚举
|
||||
|
||||
枚举类型可以具有递归结构,就是说,枚举用例的关联值类型可以是枚举类型自身。然而,枚举类型的实例具有值语义,这意味着它们在内存中有着固定的位置。为了支持递归,编译器必须插入一个间接层。
|
||||
枚举类型可以具有递归结构,就是说,枚举用例的关联值类型可以是枚举类型自身。然而,枚举类型的实例具有值语义,这意味着它们在内存中有固定布局。为了支持递归,编译器必须插入一个间接层。
|
||||
|
||||
要让某个枚举用例支持递归,使用 `indirect` 声明修饰符标记该用例。
|
||||
|
||||
@ -623,20 +610,20 @@ enum Tree<T> {
|
||||
被 `indirect` 修饰符标记的枚举用例必须有一个关联值。使用 `indirect` 修饰符标记的枚举类型可以既包含有关联值的用例,同时还可包含没有关联值的用例。但是,它不能再单独使用 `indirect` 修饰符来标记某个用例。
|
||||
|
||||
<a name="enumerations_with_cases_of_a_raw-value_type"></a>
|
||||
### 包含原始值类型的枚举
|
||||
### 拥有原始值的枚举用例
|
||||
|
||||
以下形式声明了一种枚举类型,其中各个枚举用例的类型均为同一种基本类型:
|
||||
|
||||
```swift
|
||||
enum <#枚举名称#>: <#原始值类型#>, <#采纳的协议#> {
|
||||
case <#枚举用例1#> = <#原始值1#>
|
||||
case <#枚举用例2#> = <#原始值2#>
|
||||
enum 枚举名称: 原始值类型, 采纳的协议 {
|
||||
case 枚举用例1 = 原始值1
|
||||
case 枚举用例2 = 原始值2
|
||||
}
|
||||
```
|
||||
|
||||
在这种形式中,每一个用例块由 `case` 关键字开始,后面紧跟一个或多个以逗号分隔的枚举用例。和第一种形式的枚举用例不同,这种形式的枚举用例包含一个基础值,叫做原始值,各个枚举用例的原始值的类型必须相同。这些原始值的类型通过原始值类型指定,必须表示一个整数,浮点数,字符串,或者字符。原始值类型必须符合 `Equatable` 协议和下列字面量转换协议中的一种:整型字面量需符合 `IntergerLiteralConvertible` 协议,浮点型字面量需符合 `FloatingPointLiteralConvertible` 协议,包含任意数量字符的字符串型字面量需符合 `StringLiteralConvertible` 协议,仅包含一个单一字符的字符串型字面量需符合 `ExtendedGraphemeClusterLiteralConvertible` 协议。每一个用例的名字和原始值必须唯一。
|
||||
在这种形式中,每一个用例块由 `case` 关键字开始,后面紧跟一个或多个以逗号分隔的枚举用例。和第一种形式的枚举用例不同,这种形式的枚举用例包含一个基础值,叫做原始值,各个枚举用例的原始值的类型必须相同。这些原始值的类型通过原始值类型指定,必须表示一个整数、浮点数、字符串或者字符。原始值类型必须符合 `Equatable` 协议和下列字面量转换协议中的一种:整型字面量需符合 `IntergerLiteralConvertible` 协议,浮点型字面量需符合 `FloatingPointLiteralConvertible` 协议,包含任意数量字符的字符串型字面量需符合 `StringLiteralConvertible` 协议,仅包含一个单一字符的字符串型字面量需符合 `ExtendedGraphemeClusterLiteralConvertible` 协议。每一个用例的名字和原始值必须唯一。
|
||||
|
||||
如果原始值类型被指定为 `Int`,则不必为用例显式地指定原始值,它们会隐式地被赋值 `0`,`1`,`2` 等。每个未被赋值的 `Int` 类型的用例会被隐式地赋值,其值为上一个用例的原始值加 `1`。
|
||||
如果原始值类型被指定为 `Int`,则不必为用例显式地指定原始值,它们会隐式地被赋值 `0`、`1`、`2` 等。每个未被赋值的 `Int` 类型的用例会被隐式地赋值,其值为上一个用例的原始值加 `1`。
|
||||
|
||||
```Swift
|
||||
enum ExampleEnum: Int {
|
||||
@ -656,7 +643,7 @@ enum WeekendDay: String {
|
||||
|
||||
在上面这个例子中,`WeekendDay.Saturday` 的原始值是 `"Saturday"`,`WeekendDay.Sunday` 的原始值是 `"Sunday"`。
|
||||
|
||||
枚举用例具有原始值的枚举类型隐式地符合定义在 Swift 标准库中的 `RawRepresentable` 协议。所以,它们拥有一个 `rawValue` 属性和一个可失败构造器 `init?(rawValue: RawValue)`。可以使用 `rawValue` 属性去获取枚举用例的原始值,例如 `ExampleEnum.B.rawValue`。还可以根据原始值来获取一个相对应的枚举用例,只需调用枚举的可失败构造器,例如 `ExampleEnum(rawValue: 5)`,这个可失败构造器返回一个可选类型的用例。要获得更多关于具有原始值的枚举用例的信息和例子,请参阅 [原始值](../chapter2/08_Enumerations.md#raw_values)。
|
||||
枚举用例具有原始值的枚举类型隐式地符合定义在 Swift 标准库中的 `RawRepresentable` 协议。所以,它们拥有一个 `rawValue` 属性和一个可失败构造器 `init?(rawValue: RawValue)`。可以使用 `rawValue` 属性去获取枚举用例的原始值,例如 `ExampleEnum.B.rawValue`。还可以根据原始值来创建一个相对应的枚举用例,只需调用枚举的可失败构造器,例如 `ExampleEnum(rawValue: 5)`,这个可失败构造器返回一个可选类型的用例。要获得更多关于具有原始值的枚举用例的信息和例子,请参阅 [原始值](../chapter2/08_Enumerations.md#raw_values)。
|
||||
|
||||
<a name="accessing_enumeration_cases"></a>
|
||||
### 访问枚举用例
|
||||
@ -712,16 +699,16 @@ enum WeekendDay: String {
|
||||
使用*结构体声明 (structure declaration)* 可以在程序中引入一个结构体类型。结构体声明使用 `struct` 关键字,遵循如下的形式:
|
||||
|
||||
```swift
|
||||
struct <#结构体名称#>: <#采纳的协议#> {
|
||||
<#多条声明#>
|
||||
struct 结构体名称: 采纳的协议 {
|
||||
多条声明
|
||||
}
|
||||
```
|
||||
|
||||
结构体内可包含零个或多个声明。这些声明可以包括存储型和计算型属性,类型属性,实例方法,类型方法,构造器,下标,类型别名,甚至其他结构体,类,和枚举声明。结构体声明不能包含析构器或者协议声明。关于结构体的详细讨论和示例,请参阅 [类和结构体](../chapter2/09_Classes_and_Structures.md)。
|
||||
结构体内可包含零个或多个声明。这些声明可以包括存储型和计算型属性、类型属性、实例方法、类型方法、构造器、下标、类型别名,甚至其他结构体、类、和枚举声明。结构体声明不能包含析构器或者协议声明。关于结构体的详细讨论和示例,请参阅 [类和结构体](../chapter2/09_Classes_and_Structures.md)。
|
||||
|
||||
结构体可以采纳任意数量的协议,但是不能继承自类,枚举或者其他结构体。
|
||||
结构体可以采纳任意数量的协议,但是不能继承自类、枚举或者其他结构体。
|
||||
|
||||
有三种方法可以创建一个声明过的结构体实例:
|
||||
有三种方法可以创建一个已声明的结构体实例:
|
||||
|
||||
* 调用结构体内声明的构造器,正如 [构造器](../chapter2/14_Initialization.md#initializers) 所述。
|
||||
|
||||
@ -753,22 +740,22 @@ struct <#结构体名称#>: <#采纳的协议#> {
|
||||
可以在程序中使用*类声明 (class declaration)* 来引入一个类。类声明使用关键字 `class`,遵循如下的形式:
|
||||
|
||||
```swift
|
||||
class <#类名#>: <#超类#>, <#采纳的协议#> {
|
||||
<#多条声明#>
|
||||
class 类名: 超类, 采纳的协议 {
|
||||
多条声明
|
||||
}
|
||||
```
|
||||
|
||||
类内可以包含零个或多个声明。这些声明可以包括存储型和计算型属性,实例方法,类型方法,构造器,析构器,下标,类型别名,甚至其他结构体,类,和枚举声明。类声明不能包含协议声明。关于类的详细讨论和示例,请参阅 [类和结构体](../chapter2/09_Classes_and_Structures.md)。
|
||||
类内可以包含零个或多个声明。这些声明可以包括存储型和计算型属性、实例方法、类型方法、构造器、唯一的析构器、下标、类型别名,甚至其他结构体、类和枚举声明。类声明不能包含协议声明。关于类的详细讨论和示例,请参阅 [类和结构体](../chapter2/09_Classes_and_Structures.md)。
|
||||
|
||||
一个类只能继承自一个超类,但是可以采纳任意数量的协议。超类紧跟在类名和冒号后面,其后跟着采纳的协议。泛型类可以继承自其它泛型类和非泛型类,但是非泛型类只能继承自其它非泛型类。当在冒号后面写泛型超类的名称时,必须写上泛型类的全名,包括它的泛型形参子句。
|
||||
|
||||
正如 [构造器声明](#initializer_declaration) 所讨论的,类可以有指定构造器和便利构造器。类的指定构造器必须初始化类中声明的所有属性,并且必须在调用超类构造器之前。
|
||||
|
||||
类可以重写属性,方法,下标,以及构造器。重写的属性,方法,下标,和指定构造器必须以 `override` 声明修饰符标记。
|
||||
类可以重写属性、方法、下标以及构造器。重写的属性、方法、下标和指定构造器必须以 `override` 声明修饰符标记。
|
||||
|
||||
为了要求子类去实现超类的构造器,使用 `required` 声明修饰符标记超类的构造器。子类实现超类构造器时也必须使用 `required` 声明修饰符。
|
||||
|
||||
虽然超类属性和方法声明可以被当前类继承,但是超类声明的指定构造器却不能。即便如此,如果当前类重写了超类的所有指定构造器,它就继承了超类的便利构造器。Swift 的类并不继承自一个通用基础类。
|
||||
虽然超类属性和方法声明可以被当前类继承,但是超类声明的指定构造器却不能。即便如此,如果当前类重写了超类的所有指定构造器,它就会继承超类的所有便利构造器。Swift 的类并不继承自一个通用基础类。
|
||||
|
||||
有两种方法来创建已声明的类的实例:
|
||||
|
||||
@ -797,17 +784,17 @@ class <#类名#>: <#超类#>, <#采纳的协议#> {
|
||||
*协议声明 (protocol declaration)* 可以为程序引入一个命名的协议类型。协议声明只能在全局区域使用 `protocol` 关键字来进行声明,并遵循如下形式:
|
||||
|
||||
```swift
|
||||
protocol <#协议名称#>: <#继承的协议#> {
|
||||
<#协议成员声明#>
|
||||
protocol 协议名称: 继承的协议 {
|
||||
协议成员声明
|
||||
}
|
||||
```
|
||||
|
||||
协议的主体包含零个或多个协议成员声明,这些成员描述了任何采纳该协议的类型必须满足的一致性要求。一个协议可以声明采纳者必须实现的某些属性、方法、构造器以及下标。协议也可以声明特殊类型的类型别名,叫做关联类型,它可以指定协议的不同声明之间的关系。协议声明不能包括类,结构体,枚举或者其它协议的声明。协议成员声明会在后面进行讨论。
|
||||
协议的主体包含零个或多个协议成员声明,这些成员描述了任何采纳该协议的类型必须满足的一致性要求。一个协议可以声明采纳者必须实现的某些属性、方法、构造器以及下标。协议也可以声明各种各样的类型别名,叫做关联类型,它可以指定协议的不同声明之间的关系。协议声明不能包括类、结构体、枚举或者其它协议的声明。协议成员声明会在后面进行讨论。
|
||||
|
||||
协议类型可以继承自任意数量的其它协议。当一个协议类型继承自其它协议的时候,来自其它协议的所有要求会聚合在一起,而且采纳当前协议的类型必须符合所有的这些要求。关于如何使用协议继承的例子,请参阅 [协议继承](../chapter2/22_Protocols.md#protocol_inheritance)。
|
||||
|
||||
> 注意
|
||||
> 也可以使用协议合成类型来集合多个协议的一致性要求,请参阅 [协议合成类型](03_Types.md#protocol_composition_type) 和 [协议合成](../chapter2/22_Protocols.md#protocol_composition)。
|
||||
> 也可以使用协议合成类型来聚合多个协议的一致性要求,请参阅 [协议合成类型](03_Types.md#protocol_composition_type) 和 [协议合成](../chapter2/22_Protocols.md#protocol_composition)。
|
||||
|
||||
可以通过类型的扩展声明来采纳协议,从而为之前声明的类型添加协议一致性。在扩展中,必须实现所有采纳协议的要求。如果该类型已经实现了所有的要求,可以让这个扩展声明的主体留空。
|
||||
|
||||
@ -855,12 +842,12 @@ protocol SomeProtocol: class {
|
||||
协议可以通过在协议声明主体中引入一个协议属性声明,来声明符合的类型必须实现的属性。协议属性声明有一种特殊的变量声明形式:
|
||||
|
||||
```swift
|
||||
var <#属性名#>: <#类型#> { get set }
|
||||
var 属性名: 类型 { get set }
|
||||
```
|
||||
|
||||
同其它协议成员声明一样,这些属性声明仅仅针对符合该协议的类型声明了 getter 和 setter 要求,你不能在协议中直接实现 getter 和 setter。
|
||||
|
||||
符合类型可以通过多种方式满足 getter 和 setter 要求。如果属性声明包含 `get` 和 `set` 关键字,符合类型就可以用可读写(实现了 getter 和 setter)的存储型变量属性或计算型属性来满足此要求,但是属性不能以常量属性或只读计算型属性实现。如果属性声明仅仅包含 `get` 关键字的话,它可以作为任意类型的属性被实现。关于如何实现协议中的属性要求的例子,请参阅 [属性要求](../chapter2/22_Protocols.md#property_requirements)
|
||||
符合类型可以通过多种方式满足 getter 和 setter 要求。如果属性声明包含 `get` 和 `set` 关键字,符合类型就可以用存储型变量属性或可读可写的计算型属性来满足此要求,但是属性不能以常量属性或只读计算型属性实现。如果属性声明仅仅包含 `get` 关键字的话,它可以作为任意类型的属性被实现。关于如何实现协议中的属性要求的例子,请参阅 [属性要求](../chapter2/22_Protocols.md#property_requirements)
|
||||
|
||||
另请参阅 [变量声明](#variable_declaration)。
|
||||
|
||||
@ -874,7 +861,7 @@ var <#属性名#>: <#类型#> { get set }
|
||||
|
||||
协议可以通过在协议声明主体中引入一个协议方法声明,来声明符合的类型必须实现的方法。协议方法声明和函数方法声明有着相同的形式,但有两项例外:它们不包括函数体,也不能包含默认参数。关于如何实现协议中的方法要求的例子,请参阅 [方法要求](../chapter2/22_Protocols.md#method_requirements)。
|
||||
|
||||
使用 `static` 声明修饰符可以在协议声明中声明一个静态方法。结构体实现这些方法时使用 `static` 声明修饰符,类在实现这些方法时,除了使用 `static` 声明修饰符,还可以选择使用 `class` 声明修饰符。通过扩展实现时亦是如此。
|
||||
使用 `static` 声明修饰符可以在协议声明中声明一个类型方法。结构体实现这些方法时使用 `static` 声明修饰符,类在实现这些方法时,除了使用 `static` 声明修饰符,还可以选择使用 `class` 声明修饰符。通过扩展实现时亦是如此。
|
||||
|
||||
另请参阅 [函数声明](#function_declaration)。
|
||||
|
||||
@ -907,7 +894,7 @@ var <#属性名#>: <#类型#> { get set }
|
||||
协议可以通过在协议声明主体中引入一个协议下标声明,来声明符合的类型必须实现的下标。协议下标声明有一个特殊的下标声明形式:
|
||||
|
||||
```swift
|
||||
subscript (<#参数列表#>) -> <#返回类型#> { get set }
|
||||
subscript (参数列表) -> 返回类型 { get set }
|
||||
```
|
||||
|
||||
下标声明只为符合类型声明了 getter 和 setter 要求。如果下标声明包含 `get` 和 `set` 关键字,符合类型也必须实现 getter 和 setter 子句。如果下标声明只包含 `get` 关键字,符合类型必须实现 getter 子句,可以选择是否实现 setter 子句。
|
||||
@ -934,29 +921,29 @@ subscript (<#参数列表#>) -> <#返回类型#> { get set }
|
||||
<a name="initializer_declaration"></a>
|
||||
## 构造器声明
|
||||
|
||||
构造器声明会为程序中的类,结构体或枚举引入构造器。构造器使用关键字 `init` 来声明,有两种基本形式。
|
||||
构造器声明会为程序中的类、结构体或枚举引入构造器。构造器使用关键字 `init` 来声明,有两种基本形式。
|
||||
|
||||
结构体,枚举,类可以有任意数量的构造器,但是类的构造器具有不同的规则和行为。不同于结构体和枚举,类有两种构造器,即指定构造器和便利构造器,请参阅 [构造过程](../chapter2/14_Initialization.md)。
|
||||
结构体、枚举、类可以有任意数量的构造器,但是类的构造器具有不同的规则和行为。不同于结构体和枚举,类有两种构造器,即指定构造器和便利构造器,请参阅 [构造过程](../chapter2/14_Initialization.md)。
|
||||
|
||||
采用如下形式声明结构体和枚举的构造器,以及类的指定构造器:
|
||||
|
||||
```swift
|
||||
init(<#参数列表#>) {
|
||||
<#构造语句#>
|
||||
init(参数列表) {
|
||||
构造语句
|
||||
}
|
||||
```
|
||||
|
||||
类的指定构造器直接将类的所有属性初始化。它不能调用类中的其他构造器,如果类有超类,它还必须调用超类的一个指定构造器。如果该类从它的超类继承了属性,必须在调用超类的指定构造器后才能修改这些属性。
|
||||
类的指定构造器直接将类的所有属性初始化。它不能调用类中的其他构造器,如果类有超类,则必须调用超类的一个指定构造器。如果该类从它的超类继承了属性,必须在调用超类的指定构造器后才能修改这些属性。
|
||||
|
||||
指定构造器只能在类声明的上下文中声明,不能在扩展声明中声明。
|
||||
指定构造器只能在类声明中声明,不能在扩展声明中声明。
|
||||
|
||||
结构体和枚举的构造器可以调用其他已声明的构造器,委托其他构造器来进行部分或者全部构造过程。
|
||||
结构体和枚举的构造器可以调用其他已声明的构造器,从而委托其他构造器来进行部分或者全部构造过程。
|
||||
|
||||
要为类声明一个便利构造器,用 `convenience` 声明修饰符来标记构造器声明:
|
||||
|
||||
```swift
|
||||
convenience init(<#参数列表#>) {
|
||||
<#构造语句#>
|
||||
convenience init(参数列表) {
|
||||
构造语句
|
||||
}
|
||||
```
|
||||
|
||||
@ -966,12 +953,12 @@ convenience init(<#参数列表#>) {
|
||||
|
||||
默认情况下,超类中的构造器不会被子类继承。但是,如果子类的所有存储型属性都有默认值,而且子类自身没有定义任何构造器,它将继承超类的构造器。如果子类重写了超类的所有指定构造器,子类将继承超类的所有便利构造器。
|
||||
|
||||
和方法,属性和下标一样,需要使用 `override` 声明修饰符标记重写的指定构造器。
|
||||
和方法、属性和下标一样,需要使用 `override` 声明修饰符标记重写的指定构造器。
|
||||
|
||||
> 注意
|
||||
> 如果使用 `required` 声明修饰符标记一个构造器,在子类中重写这种构造器时,无需使用 `override` 修饰符。
|
||||
|
||||
就像函数和方法,构造器也可以抛出或者重抛出错误,你可以在构造器参数列表的圆括号之后使用 `throws` 或 `rethrows` 关键字来表明相应的抛出行为。
|
||||
就像函数和方法,构造器也可以抛出或者重抛错误,你可以在构造器参数列表的圆括号之后使用 `throws` 或 `rethrows` 关键字来表明相应的抛出行为。
|
||||
|
||||
关于在不同类型中声明构造器的例子,请参阅 [构造过程](../chapter2/14_Initialization.md)。
|
||||
|
||||
@ -1006,11 +993,11 @@ if let actualInstance = SomeStruct(input: "Hello") {
|
||||
}
|
||||
```
|
||||
|
||||
结构体或者枚举的可失败构造器可以在构造器实现中的任意位置返回 `nil`。
|
||||
可失败构造器可以在构造器实现中的任意位置返回 `nil`。
|
||||
|
||||
可失败构造器可以委托任意种类的构造器。非可失败可以委托其它非可失败构造器或者 `init!` 可失败构造器。非可失败构造器可以委托超类的 `init?` 可失败指定构造器,但是需要使用强制解包,例如 `super.init()!`。
|
||||
|
||||
构造过程的失败通过构造器委托来传递。具体来说,如果可失败构造器委托的可失败构造器构造过程失败并返回 `nil`,那么该可失败构造器也会构造失败并隐式地返回 `nil`。如果非可失败构造器委托的 `init!` 可失败构造器构造失败并返回了 `nil`,那么会发生运行时错误(如同使用 `!` 操作符去强制解包一个值为 `nil` 的可选值)。
|
||||
构造过程失败通过构造器委托来传递。具体来说,如果可失败构造器委托的可失败构造器构造过程失败并返回 `nil`,那么该可失败构造器也会构造失败并隐式地返回 `nil`。如果非可失败构造器委托的 `init!` 可失败构造器构造失败并返回了 `nil`,那么会发生运行时错误(如同使用 `!` 操作符去强制解包一个值为 `nil` 的可选值)。
|
||||
|
||||
子类可以用任意种类的指定构造器重写超类的可失败指定构造器,但是只能用非可失败指定构造器重写超类的非可失败指定构造器。
|
||||
|
||||
@ -1035,7 +1022,7 @@ if let actualInstance = SomeStruct(input: "Hello") {
|
||||
|
||||
```swift
|
||||
deinit {
|
||||
<#语句#>
|
||||
语句
|
||||
}
|
||||
```
|
||||
|
||||
@ -1055,21 +1042,21 @@ deinit {
|
||||
<a name="extension_declaration"></a>
|
||||
## 扩展声明
|
||||
|
||||
*扩展声明 (extension declaration)* 可以扩展一个现存的类,结构体,和枚举类型的行为。扩展声明使用关键字 `extension`,遵循如下格式:
|
||||
*扩展声明 (extension declaration)* 可以扩展一个现存的类、结构体和枚举类型的行为。扩展声明使用关键字 `extension`,遵循如下格式:
|
||||
|
||||
```swift
|
||||
extension <#类型名称#>: <#采纳的协议#> {
|
||||
<#声明语句#>
|
||||
extension 类型名称: 采纳的协议 {
|
||||
声明语句
|
||||
}
|
||||
```
|
||||
|
||||
扩展声明体可包含零个或多个声明语句。这些声明语句可以包括计算型属性,计算型类型属性,实例方法,类型方法,构造器,下标声明,甚至其他结构体,类,和枚举声明。扩展声明不能包含析构器,协议声明,存储型属性,属性观察器,或其他扩展声明。关于扩展声明的详细讨论,以及各种扩展声明的例子,请参阅 [扩展](../chapter2/21_Extensions.md)。
|
||||
扩展声明体可包含零个或多个声明语句。这些声明语句可以包括计算型属性、计算型类型属性、实例方法、类型方法、构造器、下标声明,甚至其他结构体、类和枚举声明。扩展声明不能包含析构器、协议声明、存储型属性、属性观察器或其他扩展声明。关于扩展声明的详细讨论,以及各种扩展声明的例子,请参阅 [扩展](../chapter2/21_Extensions.md)。
|
||||
|
||||
扩展声明可以为现存的类,结构体,枚举添加协议一致性,但是不能为类添加超类,因此,在扩展声明的类型名称的冒号后面仅能指定一个协议列表。
|
||||
扩展声明可以为现存的类、结构体、枚举添加协议一致性,但是不能为类添加超类,因此在扩展声明的类型名称的冒号后面仅能指定一个协议列表。
|
||||
|
||||
现存类型的属性,方法,构造器不能在扩展中被重写。
|
||||
现存类型的属性、方法、构造器不能在扩展中被重写。
|
||||
|
||||
扩展声明可以包含构造器声明。这意味着,如果被扩展的类型在其他模块中定义,构造器声明必须委托另一个在那个模块中声明的构造器,以此确保该类型能被正确地初始化。
|
||||
扩展声明可以包含构造器声明。这意味着,如果被扩展的类型在其他模块中定义,构造器声明必须委托另一个在那个模块中声明的构造器,以确保该类型能被正确地初始化。
|
||||
|
||||
<a name="grammer_of_an_extension_declaration"></a>
|
||||
> 扩展声明语法
|
||||
@ -1081,30 +1068,30 @@ extension <#类型名称#>: <#采纳的协议#> {
|
||||
<a name="subscript_declaration"></a>
|
||||
## 下标声明
|
||||
|
||||
*下标声明 (subscript declaration)* 用于为特定类型的对象添加下标支持,通常也用于为访问集合,列表和序列中的元素提供语法便利。下标声明使用关键字 `subscript`,形式如下:
|
||||
*下标声明 (subscript declaration)* 用于为特定类型的对象添加下标支持,通常也用于为访问集合、列表和序列中的元素提供语法便利。下标声明使用关键字 `subscript`,形式如下:
|
||||
|
||||
```swift
|
||||
subscript (<#参数列表#>) -> <#返回类型#> {
|
||||
subscript (参数列表) -> 返回类型 {
|
||||
get {
|
||||
<#语句#>
|
||||
语句
|
||||
}
|
||||
set(<#setter 名称#>) {
|
||||
<#语句#>
|
||||
set(setter 名称) {
|
||||
语句
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
下标声明只能出现在类,结构体,枚举,扩展和协议声明的上下文中。
|
||||
下标声明只能出现在类、结构体、枚举、扩展和协议的声明中。
|
||||
|
||||
参数列表指定一个或多个用于在相关类型的下标表达式中访问元素的索引(例如,表达式 `object[i]` 中的 `i`)。索引可以是任意类型,但是必须包含类型标注。返回类型指定被访问的元素的类型。
|
||||
参数列表指定一个或多个用于在相关类型的下标表达式中访问元素的索引(例如,表达式 `object[i]` 中的 `i`)。索引可以是任意类型,但是必须包含类型标注。返回类型指定了被访问的元素的类型。
|
||||
|
||||
和计算型属性一样,下标声明支持对元素的读写操作。getter 用于读取值,setter 用于写入值。setter 子句是可选的,当仅需要一个 getter 子句时,可以将二者都忽略,直接返回请求的值即可。但是,如果提供了 setter 子句,就必须提供 getter 子句。
|
||||
|
||||
圆括号以及其中的 setter 名称是可选的。如果提供了 setter 名称,它会作为 setter 的参数名称。如果不提供 setter 名称,那么 setter 的参数名称默认是 `value`。setter 名称的类型必须与返回类型相同。
|
||||
|
||||
可以重载下标,只要参数列表或返回类型与先前不同即可。还可以重写继承自超类的下标,此时必须使用 `override` 声明修饰符声明被重写的下标。
|
||||
可以重载下标,只要参数列表或返回类型不同即可。还可以重写继承自超类的下标,此时必须使用 `override` 声明修饰符声明被重写的下标。
|
||||
|
||||
同样可以在协议声明的上下文中声明下标,正如 [协议下标声明](#protocol_subscript_declaration) 中所述。
|
||||
同样可以在协议声明中声明下标,正如 [协议下标声明](#protocol_subscript_declaration) 中所述。
|
||||
|
||||
更多关于下标的信息和例子,请参阅 [下标](../chapter2/12_Subscripts.md)。
|
||||
|
||||
@ -1131,9 +1118,9 @@ subscript (<#参数列表#>) -> <#返回类型#> {
|
||||
下面的形式声明了一个新的中缀运算符:
|
||||
|
||||
```swift
|
||||
infix operator <#运算符名称#> {
|
||||
precedence <#优先级#>
|
||||
associativity <#结合性#>
|
||||
infix operator 运算符名称 {
|
||||
precedence 优先级
|
||||
associativity 结合性
|
||||
}
|
||||
```
|
||||
|
||||
@ -1143,14 +1130,14 @@ infix operator <#运算符名称#> {
|
||||
|
||||
运算符的优先级可以指定在没有括号包围的情况下,运算符与其运算对象如何结合。可以使用上下文相关的关键字 `precedence` 以及紧随其后的优先级数字来指定一个运算符的优先级。优先级可以是 `0` 到 `255` 之间的任何十进制整数。与十进制整数字面量不同的是,它不可以包含任何下划线字符。尽管优先级是一个特定的数字,但它仅用作与另一个运算符的优先级比较大小。也就是说,当两个运算符为同一个运算对象竞争时,例如 `2 + 3 * 5`,优先级更高的运算符将优先参与运算。
|
||||
|
||||
运算符的结合性可以指定在没有括号包围的情况下,多个优先级相同的运算符将如何组合。可以使用上下文相关的关键字 `associativity` 以及紧随其后的结合性关键字来指定运算符的结合性,结合性关键字也是上下文相关的,包括 `left`,`right`,和 `none`。左结合运算符以从左到右的顺序进行组合。例如,减法运算符(`-`)具有左结合性,因此 `4 - 5 - 6` 以 `(4 - 5) - 6` 的形式组合,其结果为 `-7`。右结合运算符以从右到左的顺序组合,而设置为 `none` 的运算符不进行组合。具有相同优先级的非结合运算符,不可以互相邻接。例如,表达式 `1 < 2 < 3` 是非法的。
|
||||
运算符的结合性可以指定在没有括号包围的情况下,多个优先级相同的运算符将如何组合。可以使用上下文相关的关键字 `associativity` 以及紧随其后的结合性关键字来指定运算符的结合性,结合性关键字也是上下文相关的,包括 `left`、`right` 和 `none`。左结合运算符以从左到右的顺序进行组合。例如,减法运算符(`-`)具有左结合性,因此 `4 - 5 - 6` 以 `(4 - 5) - 6` 的形式组合,其结果为 `-7`。右结合运算符以从右到左的顺序组合,而设置为 `none` 的运算符不进行组合。具有相同优先级的非结合运算符,不可以互相邻接。例如,表达式 `1 < 2 < 3` 是非法的。
|
||||
|
||||
声明时不指定任何优先级或结合性的中缀运算符,优先级为 `100`,结合性为 `none`。
|
||||
|
||||
下面的形式声明了一个新的前缀运算符:
|
||||
|
||||
```swift
|
||||
prefix operator <#运算符名称#> {}
|
||||
prefix operator 运算符名称 {}
|
||||
```
|
||||
|
||||
出现在运算对象前边的前缀运算符是一元运算符,例如表达式 `!a` 中的前缀非运算符(`!`)。
|
||||
@ -1160,10 +1147,10 @@ prefix operator <#运算符名称#> {}
|
||||
下面的形式声明了一个新的后缀运算符:
|
||||
|
||||
```swift
|
||||
postfix operator <#运算符名称#> {}
|
||||
postfix operator 运算符名称 {}
|
||||
```
|
||||
|
||||
紧跟在运算对象后边的后缀运算符是一元运算符,例如表达式 `i!` 中的后缀强制解包运算符(`!`)。
|
||||
紧跟在运算对象后边的后缀运算符是一元运算符,例如表达式 `a!` 中的后缀强制解包运算符(`!`)。
|
||||
|
||||
和前缀运算符一样,后缀运算符的声明中不指定优先级,而且后缀运算符是非结合的。
|
||||
|
||||
@ -1206,7 +1193,7 @@ postfix operator <#运算符名称#> {}
|
||||
|
||||
`final`
|
||||
|
||||
该修饰符用于修饰类或类中的属性,方法,以及下标。如果用它修饰一个类,那么这个类不能被继承。如果用它修饰类中的属性,方法或下标,那么它们不能在子类中被重写。
|
||||
该修饰符用于修饰类或类中的属性、方法以及下标。如果用它修饰一个类,那么这个类不能被继承。如果用它修饰类中的属性、方法或下标,那么它们不能在子类中被重写。
|
||||
|
||||
`lazy`
|
||||
|
||||
@ -1214,7 +1201,7 @@ postfix operator <#运算符名称#> {}
|
||||
|
||||
`optional`
|
||||
|
||||
该修饰符用于修饰协议中的属性,方法,以及下标成员,表示符合类型不必实现这些成员要求。
|
||||
该修饰符用于修饰协议中的属性、方法以及下标成员,表示符合类型可以不实现这些成员要求。
|
||||
|
||||
只能将 `optional` 修饰符用于被 `objc` 特性标记的协议。这样一来,就只有类类型可以采纳并符合拥有可选成员要求的协议。关于如何使用 `optional` 修饰符,以及如何访问可选协议成员(比如,不确定符合类型是否已经实现了这些可选成员)的信息,请参阅 [可选协议要求](../chapter2/22_Protocols.md#optional_protocol_requirements)。
|
||||
|
||||
@ -1229,7 +1216,7 @@ postfix operator <#运算符名称#> {}
|
||||
<a name="access_control_levels"></a>
|
||||
### 访问控制级别
|
||||
|
||||
Swift 提供了三个级别的访问控制:`public`,`internal` 和 `private`。可以使用以下任意一种访问级别修饰符来指定声明的访问级别。访问控制在 [访问控制](../chapter2/24_Access_Control.md) 中有详细讨论。
|
||||
Swift 提供了三个级别的访问控制:`public`、`internal` 和 `private`。可以使用以下任意一种访问级别修饰符来指定声明的访问级别。访问控制在 [访问控制](../chapter2/24_Access_Control.md) 中有详细讨论。
|
||||
|
||||
`public`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user