Merge pull request #171 from stanzhai/develop

【校对】人工逐节校对中,完善代码风格,语法说明等
This commit is contained in:
SiweiShen
2014-06-14 18:24:13 +08:00
21 changed files with 2007 additions and 1902 deletions

View File

@ -1,5 +1,4 @@
> 翻译numbbbbb > 翻译numbbbbb
> 校对yeahdongcn > 校对yeahdongcn
# 关于 Swift # 关于 Swift

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
> 翻译numbbbbb, lyuka, JaySurplus > 翻译numbbbbb, lyuka, JaySurplus
> 校对lslxdx
> 校对lslxdx
# 基础部分 # 基础部分
----------------- -----------------
@ -42,9 +41,10 @@ Swift 是一个类型安全的语言可选就是一个很好的例子。Swift
常量和变量必须在使用前声明,用`let`来声明常量,用`var`来声明变量。下面的例子展示了如何用常量和变量来记录用户尝试登录的次数: 常量和变量必须在使用前声明,用`let`来声明常量,用`var`来声明变量。下面的例子展示了如何用常量和变量来记录用户尝试登录的次数:
let maximumNumberOfLoginAttempts = 10 ```swift
var currentLoginAttempt = 0 let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
```
这两行代码可以被理解为: 这两行代码可以被理解为:
@ -54,10 +54,11 @@ Swift 是一个类型安全的语言可选就是一个很好的例子。Swift
你可以在一行中声明多个常量或者多个变量,用逗号隔开: 你可以在一行中声明多个常量或者多个变量,用逗号隔开:
var x = 0.0, y = 0.0, z = 0.0 ```swift
var x = 0.0, y = 0.0, z = 0.0
```
>注意: >注意:
>
如果你的代码中有不需要改变的值,请使用`let`关键字将它声明为常量。只将需要改变的值声明为变量。 如果你的代码中有不需要改变的值,请使用`let`关键字将它声明为常量。只将需要改变的值声明为变量。
### 类型标注 ### 类型标注
@ -66,7 +67,9 @@ Swift 是一个类型安全的语言可选就是一个很好的例子。Swift
这个例子给`welcomeMessage`变量添加了类型标注,表示这个变量可以存储`String`类型的值: 这个例子给`welcomeMessage`变量添加了类型标注,表示这个变量可以存储`String`类型的值:
var welcomeMessage: String ```swift
var welcomeMessage: String
```
声明中的冒号代表着“是...类型”,所以这行代码可以被理解为: 声明中的冒号代表着“是...类型”,所以这行代码可以被理解为:
@ -76,63 +79,74 @@ Swift 是一个类型安全的语言可选就是一个很好的例子。Swift
`welcomeMessage`变量现在可以被设置成任意字符串: `welcomeMessage`变量现在可以被设置成任意字符串:
welcomeMessage = "Hello" ```swift
welcomeMessage = "Hello"
```
> 注意: > 注意:
>
一般来说你很少需要写类型标注。如果你在声明常量或者变量的时候赋了一个初始值Swift可以推断出这个常量或者变量的类型请参考[类型安全和类型推断](#type_safety_and_type_inference)。在上面的例子中,没有给`welcomeMessage`赋初始值,所以变量`welcomeMessage`的类型是通过一个类型标注指定的,而不是通过初始值推断的。 一般来说你很少需要写类型标注。如果你在声明常量或者变量的时候赋了一个初始值Swift可以推断出这个常量或者变量的类型请参考[类型安全和类型推断](#type_safety_and_type_inference)。在上面的例子中,没有给`welcomeMessage`赋初始值,所以变量`welcomeMessage`的类型是通过一个类型标注指定的,而不是通过初始值推断的。
### 常量和变量的命名 ### 常量和变量的命名
你可以用任何你喜欢的字符作为常量和变量名,包括 Unicode 字符: 你可以用任何你喜欢的字符作为常量和变量名,包括 Unicode 字符:
let π = 3.14159 ```swift
let 你好 = "你好世界" let π = 3.14159
let 🐶🐮 = "dogcow" let 你好 = "你好世界"
let 🐶🐮 = "dogcow"
```
常量与变量名不能包含数学符号箭头保留的或者非法的Unicode 码位,连线与制表符。也不能以数字开头,但是可以在常量与变量名的其他地方包含数字。 常量与变量名不能包含数学符号箭头保留的或者非法的Unicode 码位,连线与制表符。也不能以数字开头,但是可以在常量与变量名的其他地方包含数字。
一旦你将常量或者变量声明为确定的类型,你就不能使用相同的名字再次进行声明,或者改变其存储的值的类型。同时,你也不能将常量与变量进行互转。 一旦你将常量或者变量声明为确定的类型,你就不能使用相同的名字再次进行声明,或者改变其存储的值的类型。同时,你也不能将常量与变量进行互转。
> 注意: > 注意:
>
如果你需要使用与Swift保留关键字相同的名称作为常量或者变量名你可以使用反引号`)将关键字包围的方式将其作为名字使用。无论如何,你应当避免使用关键字作为常量或变量名,除非你别无选择。 如果你需要使用与Swift保留关键字相同的名称作为常量或者变量名你可以使用反引号`)将关键字包围的方式将其作为名字使用。无论如何,你应当避免使用关键字作为常量或变量名,除非你别无选择。
你可以更改现有的变量值为其他同类型的值,在下面的例子中,`friendlyWelcome`的值从`"Hello!"`改为了`"Bonjour!"`: 你可以更改现有的变量值为其他同类型的值,在下面的例子中,`friendlyWelcome`的值从`"Hello!"`改为了`"Bonjour!"`:
var friendlyWelcome = "Hello!" ```swift
friendlyWelcome = "Bonjour!" var friendlyWelcome = "Hello!"
// friendlyWelcome 现在是 "Bonjour!" friendlyWelcome = "Bonjour!"
// friendlyWelcome 现在是 "Bonjour!"
```
与变量不同,常量的值一旦被确定就不能更改了。尝试这样做会导致编译时报错: 与变量不同,常量的值一旦被确定就不能更改了。尝试这样做会导致编译时报错:
let languageName = "Swift" ```swift
languageName = "Swift++" let languageName = "Swift"
// 这会报编译时错误 - languageName 不可改变 languageName = "Swift++"
// 这会报编译时错误 - languageName 不可改变
```
### 输出常量和变量 ### 输出常量和变量
你可以用`println`函数来输出当前常量或变量的值: 你可以用`println`函数来输出当前常量或变量的值:
println(friendlyWelcome) ```swift
// 输出 "Bonjour!" println(friendlyWelcome)
// 输出 "Bonjour!"
```
`println`是一个用来输出的全局函数,输出的内容会在最后换行。如果你用 Xcode`println`将会输出内容到“console”面板上。(另一种函数叫`print`,唯一区别是在输出内容最后不会换行。) `println`是一个用来输出的全局函数,输出的内容会在最后换行。如果你用 Xcode`println`将会输出内容到“console”面板上。(另一种函数叫`print`,唯一区别是在输出内容最后不会换行。)
`println`函数输出传入的`String`值: `println`函数输出传入的`String`值:
println("This is a string") ```swift
// 输出 "This is a string" println("This is a string")
// 输出 "This is a string"
```
与 Cocoa 里的`NSLog`函数类似的是,`println`函数可以输出更复杂的信息。这些信息可以包含当前常量和变量的值。 与 Cocoa 里的`NSLog`函数类似的是,`println`函数可以输出更复杂的信息。这些信息可以包含当前常量和变量的值。
Swift 用_字符串插值string interpolation_的方式把常量名或者变量名当做占位符加入到长字符串中Swift 会用当前常量或变量的值替换这些占位符。将常量或变量名放入圆括号中,并在开括号前使用反斜杠将其转义: Swift 用_字符串插值string interpolation_的方式把常量名或者变量名当做占位符加入到长字符串中Swift 会用当前常量或变量的值替换这些占位符。将常量或变量名放入圆括号中,并在开括号前使用反斜杠将其转义:
println("The current value of friendlyWelcome is \(friendlyWelcome)") ```swift
// 输出 "The current value of friendlyWelcome is Bonjour! println("The current value of friendlyWelcome is \(friendlyWelcome)")
// 输出 "The current value of friendlyWelcome is Bonjour!
```
> 注意: > 注意:
>
字符串插值所有可用的选项,请参考[字符串插值](03_Strings_and_Characters.html#string_interpolation)。 字符串插值所有可用的选项,请参考[字符串插值](03_Strings_and_Characters.html#string_interpolation)。
<a name="comments"></a> <a name="comments"></a>
@ -141,18 +155,24 @@ Swift 用_字符串插值string interpolation_的方式把常量名或者
Swift 中的注释与C 语言的注释非常相似。单行注释以双正斜杠(`//`)作为起始标记: Swift 中的注释与C 语言的注释非常相似。单行注释以双正斜杠(`//`)作为起始标记:
// 这是一个注释 ```swift
// 这是一个注释
```
你也可以进行多行注释,其起始标记为单个正斜杠后跟随一个星号(`/*`),终止标记为一个星号后跟随单个正斜杠(`*/`: 你也可以进行多行注释,其起始标记为单个正斜杠后跟随一个星号(`/*`),终止标记为一个星号后跟随单个正斜杠(`*/`:
/* 这是一个, ```swift
多行注释 */ /* 这是一个,
多行注释 */
```
与 C 语言多行注释不同Swift 的多行注释可以嵌套在其它的多行注释之中。你可以先生成一个多行注释块,然后在这个注释块之中再嵌套成第二个多行注释。终止注释时先插入第二个注释块的终止标记,然后再插入第一个注释块的终止标记: 与 C 语言多行注释不同Swift 的多行注释可以嵌套在其它的多行注释之中。你可以先生成一个多行注释块,然后在这个注释块之中再嵌套成第二个多行注释。终止注释时先插入第二个注释块的终止标记,然后再插入第一个注释块的终止标记:
/* 这是第一个多行注释的开头 ```swift
/* 这是第二个被嵌套的多行注释 */ /* 这是第一个多行注释的开头
这是第一个多行注释的结尾 */ /* 这是第二个被嵌套的多行注释 */
这是第一个多行注释的结尾 */
```
通过运用嵌套多行注释,你可以快速方便的注释掉一大段代码,即使这段代码之中已经含有了多行注释块。 通过运用嵌套多行注释,你可以快速方便的注释掉一大段代码,即使这段代码之中已经含有了多行注释块。
@ -160,8 +180,10 @@ Swift 中的注释与C 语言的注释非常相似。单行注释以双正斜杠
## 分号 ## 分号
与其他大部分编程语言不同Swift 并不强制要求你在每条语句的结尾处使用分号(`;`),当然,你也可以按照你自己的习惯添加分号。有一种情况下必须要用分号,即你打算在同一行内写多条独立的语句: 与其他大部分编程语言不同Swift 并不强制要求你在每条语句的结尾处使用分号(`;`),当然,你也可以按照你自己的习惯添加分号。有一种情况下必须要用分号,即你打算在同一行内写多条独立的语句:
let cat = "🐱"; println(cat) ```swift
// 输出 "🐱" let cat = "🐱"; println(cat)
// 输出 "🐱"
```
<a name="integers"></a> <a name="integers"></a>
## 整数 ## 整数
@ -174,8 +196,10 @@ Swift 提供了81632和64位的有符号和无符号整数类型。这些
你可以访问不同整数类型的`min`和`max`属性来获取对应类型的最大值和最小值: 你可以访问不同整数类型的`min`和`max`属性来获取对应类型的最大值和最小值:
let minValue = UInt8.min // minValue 为 0是 UInt8 类型的最小值 ```swift
let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型的最 let minValue = UInt8.min // minValue 为 0,是 UInt8 类型的最
let maxValue = UInt8.max // maxValue 为 255是 UInt8 类型的最大值
```
### Int ### Int
@ -193,8 +217,7 @@ Swift 也提供了一个特殊的无符号类型`UInt`,长度与当前平台
* 在32位平台上`UInt`和`UInt32`长度相同。 * 在32位平台上`UInt`和`UInt32`长度相同。
* 在64位平台上`UInt`和`UInt64`长度相同。 * 在64位平台上`UInt`和`UInt64`长度相同。
> 注意: > 注意:
>
尽量不要使用`UInt`,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用`Int`,即使你要存储的值已知是非负的。统一使用`Int`可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推测,请参考[类型安全和类型推测](#type_safety_and_type_inference)。 尽量不要使用`UInt`,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用`Int`,即使你要存储的值已知是非负的。统一使用`Int`可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推测,请参考[类型安全和类型推测](#type_safety_and_type_inference)。
<a name="floating-point_numbers"></a> <a name="floating-point_numbers"></a>
@ -207,8 +230,7 @@ Swift 也提供了一个特殊的无符号类型`UInt`,长度与当前平台
* `Double`表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。 * `Double`表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。
* `Float`表示32位浮点数。精度要求不高的话可以使用此类型。 * `Float`表示32位浮点数。精度要求不高的话可以使用此类型。
> 注意: > 注意:
>
`Double`精确度很高至少有15位数字而`Float`最少只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围。 `Double`精确度很高至少有15位数字而`Float`最少只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围。
<a name="type_safety_and_type_inference"></a> <a name="type_safety_and_type_inference"></a>
@ -226,20 +248,26 @@ Swift 是一个_类型安全type safe_的语言。类型安全的语言可
例如,如果你给一个新常量赋值`42`并且没有标明类型Swift 可以推测出常量类型是`Int`,因为你给它赋的初始值看起来像一个整数: 例如,如果你给一个新常量赋值`42`并且没有标明类型Swift 可以推测出常量类型是`Int`,因为你给它赋的初始值看起来像一个整数:
let meaningOfLife = 42 ```swift
// meaningOfLife 会被推测为 Int 类型 let meaningOfLife = 42
// meaningOfLife 会被推测为 Int 类型
```
同理如果你没有给浮点字面量标明类型Swift 会推测你想要的是`Double` 同理如果你没有给浮点字面量标明类型Swift 会推测你想要的是`Double`
let pi = 3.14159 ```swift
// pi 会被推测为 Double 类型 let pi = 3.14159
// pi 会被推测为 Double 类型
```
当推测浮点数的类型时Swift 总是会选择`Double`而不是`Float`。 当推测浮点数的类型时Swift 总是会选择`Double`而不是`Float`。
如果表达式中同时出现了整数和浮点数,会被推测为`Double`类型: 如果表达式中同时出现了整数和浮点数,会被推测为`Double`类型:
let anotherPi = 3 + 0.14159 ```swift
// anotherPi 会被推测为 Double 类型 let anotherPi = 3 + 0.14159
// anotherPi 会被推测为 Double 类型
```
原始值`3`没有显式声明类型,而表达式中出现了一个浮点字面量,所以表达式会被推测为`Double`类型。 原始值`3`没有显式声明类型,而表达式中出现了一个浮点字面量,所以表达式会被推测为`Double`类型。
@ -255,10 +283,12 @@ Swift 是一个_类型安全type safe_的语言。类型安全的语言可
下面的所有整数字面量的十进制值都是`17`: 下面的所有整数字面量的十进制值都是`17`:
let decimalInteger = 17 ```swift
let binaryInteger = 0b10001 // 二进制的17 let decimalInteger = 17
let octalInteger = 0o21 // 进制的17 let binaryInteger = 0b10001 // 进制的17
let hexadecimalInteger = 0x11 // 十六进制的17 let octalInteger = 0o21 // 进制的17
let hexadecimalInteger = 0x11 // 十六进制的17
```
浮点字面量可以是十进制(没有前缀)或者是十六进制(前缀是`0x`。小数点两边必须有至少一个十进制数字或者是十六进制的数字。浮点字面量还有一个可选的_指数exponent_在十进制浮点数中通过大写或者小写的`e`来指定,在十六进制浮点数中通过大写或者小写的`p`来指定。 浮点字面量可以是十进制(没有前缀)或者是十六进制(前缀是`0x`。小数点两边必须有至少一个十进制数字或者是十六进制的数字。浮点字面量还有一个可选的_指数exponent_在十进制浮点数中通过大写或者小写的`e`来指定,在十六进制浮点数中通过大写或者小写的`p`来指定。
@ -272,15 +302,19 @@ Swift 是一个_类型安全type safe_的语言。类型安全的语言可
下面的这些浮点字面量都等于十进制的`12.1875` 下面的这些浮点字面量都等于十进制的`12.1875`
let decimalDouble = 12.1875 ```swift
let exponentDouble = 1.21875e1 let decimalDouble = 12.1875
let hexadecimalDouble = 0xC.3p0 let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
```
数值类字面量可以包括额外的格式来增强可读性。整数和浮点数都可以添加额外的零并且包含下划线,并不会影响字面量: 数值类字面量可以包括额外的格式来增强可读性。整数和浮点数都可以添加额外的零并且包含下划线,并不会影响字面量:
let paddedDouble = 000123.456 ```swift
let oneMillion = 1_000_000 let paddedDouble = 000123.456
let justOverOneMillion = 1_000_000.000_000_1 let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
```
<a name="numeric_type_conversion"></a> <a name="numeric_type_conversion"></a>
## 数值型类型转换 ## 数值型类型转换
@ -292,18 +326,22 @@ Swift 是一个_类型安全type safe_的语言。类型安全的语言可
不同整数类型的变量和常量可以存储不同范围的数字。`Int8`类型的常量或者变量可以存储的数字范围是`-128`~`127`,而`UInt8`类型的常量或者变量能存储的数字范围是`0`~`255`。如果数字超出了常量或者变量可存储的范围,编译的时候会报错: 不同整数类型的变量和常量可以存储不同范围的数字。`Int8`类型的常量或者变量可以存储的数字范围是`-128`~`127`,而`UInt8`类型的常量或者变量能存储的数字范围是`0`~`255`。如果数字超出了常量或者变量可存储的范围,编译的时候会报错:
let cannotBeNegative: UInt8 = -1 ```swift
// UInt8 类型不能存储负数,所以会报错 let cannotBeNegative: UInt8 = -1
let tooBig: Int8 = Int8.max + 1 // UInt8 类型不能存储负数,所以会报错
// Int8 类型不能存储超过最大值的数,所以会报错 let tooBig: Int8 = Int8.max + 1
// Int8 类型不能存储超过最大值的数,所以会报错
```
由于每种整数类型都可以存储不同范围的值,所以你必须根据不同情况选择性使用数值型类型转换。这种选择性使用的方式,可以预防隐式转换的错误并让你的代码中的类型转换意图变得清晰。 由于每种整数类型都可以存储不同范围的值,所以你必须根据不同情况选择性使用数值型类型转换。这种选择性使用的方式,可以预防隐式转换的错误并让你的代码中的类型转换意图变得清晰。
要将一种数字类型转换成另一种,你要用当前值来初始化一个期望类型的新数字,这个数字的类型就是你的目标类型。在下面的例子中,常量`twoThousand`是`UInt16`类型,然而常量`one`是`UInt8`类型。它们不能直接相加,因为它们类型不同。所以要调用`UInt16(one)`来创建一个新的`UInt16`数字并用`one`的值来初始化,然后使用这个新数字来计算: 要将一种数字类型转换成另一种,你要用当前值来初始化一个期望类型的新数字,这个数字的类型就是你的目标类型。在下面的例子中,常量`twoThousand`是`UInt16`类型,然而常量`one`是`UInt8`类型。它们不能直接相加,因为它们类型不同。所以要调用`UInt16(one)`来创建一个新的`UInt16`数字并用`one`的值来初始化,然后使用这个新数字来计算:
let twoThousand: UInt16 = 2_000 ```swift
let one: UInt8 = 1 let twoThousand: UInt16 = 2_000
let twoThousandAndOne = twoThousand + UInt16(one) let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
```
现在两个数字的类型都是`UInt16`,可以进行相加。目标常量`twoThousandAndOne`的类型被推测为`UInt16`,因为它是两个`UInt16`值的和。 现在两个数字的类型都是`UInt16`,可以进行相加。目标常量`twoThousandAndOne`的类型被推测为`UInt16`,因为它是两个`UInt16`值的和。
@ -313,22 +351,25 @@ Swift 是一个_类型安全type safe_的语言。类型安全的语言可
整数和浮点数的转换必须显式指定类型: 整数和浮点数的转换必须显式指定类型:
let three = 3 ```swift
let pointOneFourOneFiveNine = 0.14159 let three = 3
let pi = Double(three) + pointOneFourOneFiveNine let pointOneFourOneFiveNine = 0.14159
// pi 等于 3.14159,所以被推测为 Double 类型 let pi = Double(three) + pointOneFourOneFiveNine
// pi 等于 3.14159,所以被推测为 Double 类型
```
这个例子中,常量`three`的值被用来创建一个`Double`类型的值,所以加号两边的数类型相同。如果不进行转换,两者无法相加。 这个例子中,常量`three`的值被用来创建一个`Double`类型的值,所以加号两边的数类型相同。如果不进行转换,两者无法相加。
浮点数到整数的反向转换同样行,整数类型可以用`Double`或者`Float`类型来初始化: 浮点数到整数的反向转换同样行,整数类型可以用`Double`或者`Float`类型来初始化:
let integerPi = Int(pi) ```swift
// integerPi 等于 3所以被推测为 Int 类型 let integerPi = Int(pi)
// integerPi 等于 3所以被推测为 Int 类型
```
当用这种方式来初始化一个新的整数值时,浮点值会被截断。也就是说`4.75`会变成`4``-3.9`会变成`-3`。 当用这种方式来初始化一个新的整数值时,浮点值会被截断。也就是说`4.75`会变成`4``-3.9`会变成`-3`。
> 注意: > 注意:
>
结合数字类常量和变量不同于结合数字类字面量。字面量`3`可以直接和字面量`0.14159`相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测。 结合数字类常量和变量不同于结合数字类字面量。字面量`3`可以直接和字面量`0.14159`相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测。
<a name="type_aliases"></a> <a name="type_aliases"></a>
@ -338,12 +379,16 @@ _类型别名type aliases_就是给现有类型定义另一个名字。你
当你想要给现有类型起一个更有意义的名字时,类型别名非常有用。假设你正在处理特定长度的外部资源的数据: 当你想要给现有类型起一个更有意义的名字时,类型别名非常有用。假设你正在处理特定长度的外部资源的数据:
typealias AudioSample = UInt16 ```swift
typealias AudioSample = UInt16
```
定义了一个类型别名之后,你可以在任何使用原始名的地方使用别名: 定义了一个类型别名之后,你可以在任何使用原始名的地方使用别名:
var maxAmplitudeFound = AudioSample.min ```swift
// maxAmplitudeFound 现在是 0 var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound 现在是 0
```
本例中,`AudioSample`被定义为`UInt16`的一个别名。因为它是别名,`AudioSample.min`实际上是`UInt16.min`,所以会给`maxAmplitudeFound`赋一个初值`0`。 本例中,`AudioSample`被定义为`UInt16`的一个别名。因为它是别名,`AudioSample.min`实际上是`UInt16.min`,所以会给`maxAmplitudeFound`赋一个初值`0`。
@ -352,35 +397,43 @@ _类型别名type aliases_就是给现有类型定义另一个名字。你
Swift 有一个基本的_布尔Boolean_类型叫做`Bool`。布尔值指_逻辑上的logical_因为它们只能是真或者假。Swift 有两个布尔常量,`true`和`false` Swift 有一个基本的_布尔Boolean_类型叫做`Bool`。布尔值指_逻辑上的logical_因为它们只能是真或者假。Swift 有两个布尔常量,`true`和`false`
let orangesAreOrange = true ```swift
let turnipsAreDelicious = false let orangesAreOrange = true
let turnipsAreDelicious = false
```
`orangesAreOrange`和`turnipsAreDelicious`的类型会被推测为`Bool`,因为它们的初值是布尔字面量。就像之前提到的`Int`和`Double`一样,如果你创建变量的时候给它们赋值`true`或者`false`,那你不需要将常量或者变量声明为`Bool`类型。初始化常量或者变量的时候如果所赋的值类型已知,就可以触发类型推测,这让 Swift 代码更加简洁并且可读性更高。 `orangesAreOrange`和`turnipsAreDelicious`的类型会被推测为`Bool`,因为它们的初值是布尔字面量。就像之前提到的`Int`和`Double`一样,如果你创建变量的时候给它们赋值`true`或者`false`,那你不需要将常量或者变量声明为`Bool`类型。初始化常量或者变量的时候如果所赋的值类型已知,就可以触发类型推测,这让 Swift 代码更加简洁并且可读性更高。
当你编写条件语句比如`if`语句的时候,布尔值非常有用: 当你编写条件语句比如`if`语句的时候,布尔值非常有用:
if turnipsAreDelicious { ```swift
println("Mmm, tasty turnips!") if turnipsAreDelicious {
} else { println("Mmm, tasty turnips!")
println("Eww, turnips are horrible.") } else {
} println("Eww, turnips are horrible.")
// 输出 "Eww, turnips are horrible." }
// 输出 "Eww, turnips are horrible."
```
条件语句,例如`if`,请参考[控制流](05_Control_Flow.html)。 条件语句,例如`if`,请参考[控制流](05_Control_Flow.html)。
如果你在需要使用`Bool`类型的地方使用了非布尔值Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误: 如果你在需要使用`Bool`类型的地方使用了非布尔值Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误:
let i = 1 ```swift
if i { let i = 1
// 这个例子不会通过编译,会报错 if i {
} // 这个例子不会通过编译,会报错
}
```
然而,下面的例子是合法的: 然而,下面的例子是合法的:
let i = 1 ```swift
if i == 1 { let i = 1
// 这个例子会编译成功 if i == 1 {
} // 这个例子会编译成功
}
```
`i == 1`的比较结果是`Bool`类型,所以第二个例子可以通过类型检查。类似`i == 1`这样的比较,请参考[基本操作符](05_Control_Flow.html)。 `i == 1`的比较结果是`Bool`类型,所以第二个例子可以通过类型检查。类似`i == 1`这样的比较,请参考[基本操作符](05_Control_Flow.html)。
@ -393,8 +446,10 @@ _元组tuples_把多个值组合成一个复合值。元组内的值可以
下面这个例子中,`(404, "Not Found")`是一个描述 _HTTP 状态码HTTP status code_的元组。HTTP 状态码是当你请求网页的时候 web 服务器返回的一个特殊值。如果你请求的网页不存在就会返回一个`404 Not Found`状态码。 下面这个例子中,`(404, "Not Found")`是一个描述 _HTTP 状态码HTTP status code_的元组。HTTP 状态码是当你请求网页的时候 web 服务器返回的一个特殊值。如果你请求的网页不存在就会返回一个`404 Not Found`状态码。
let http404Error = (404, "Not Found") ```swift
// http404Error 的类型是 (Int, String),值是 (404, "Not Found") let http404Error = (404, "Not Found")
// http404Error 的类型是 (Int, String),值是 (404, "Not Found")
```
`(404, "Not Found")`元组把一个`Int`值和一个`String`值组合起来表示 HTTP 状态码的两个部分:一个数字和一个人类可读的描述。这个元组可以被描述为“一个类型为`(Int, String)`的元组”。 `(404, "Not Found")`元组把一个`Int`值和一个`String`值组合起来表示 HTTP 状态码的两个部分:一个数字和一个人类可读的描述。这个元组可以被描述为“一个类型为`(Int, String)`的元组”。
@ -402,40 +457,49 @@ _元组tuples_把多个值组合成一个复合值。元组内的值可以
你可以将一个元组的内容_分解decompose_成单独的常量和变量然后你就可以正常使用它们了 你可以将一个元组的内容_分解decompose_成单独的常量和变量然后你就可以正常使用它们了
let (statusCode, statusMessage) = http404Error ```swift
println("The status code is \(statusCode)") let (statusCode, statusMessage) = http404Error
// 输出 "The status code is 404" println("The status code is \(statusCode)")
println("The status message is \(statusMessage)") // 输出 "The status code is 404"
// 输出 "The status message is Not Found" println("The status message is \(statusMessage)")
// 输出 "The status message is Not Found"
```
如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线(`_`)标记: 如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线(`_`)标记:
let (justTheStatusCode, _) = http404Error ```swift
println("The status code is \(justTheStatusCode)") let (justTheStatusCode, _) = http404Error
// 输出 "The status code is 404" println("The status code is \(justTheStatusCode)")
// 输出 "The status code is 404"
```
此外,你还可以通过下标来访问元组中的单个元素,下标从零开始: 此外,你还可以通过下标来访问元组中的单个元素,下标从零开始:
println("The status code is \(http404Error.0)") ```swift
// 输出 "The status code is 404" println("The status code is \(http404Error.0)")
println("The status message is \(http404Error.1)") // 输出 "The status code is 404"
// 输出 "The status message is Not Found" println("The status message is \(http404Error.1)")
// 输出 "The status message is Not Found"
```
你可以在定义元组的时候给单个元素命名: 你可以在定义元组的时候给单个元素命名:
let http200Status = (statusCode: 200, description: "OK") ```swift
let http200Status = (statusCode: 200, description: "OK")
```
给元组中的元素命名后,你可以通过名字来获取这些元素的值: 给元组中的元素命名后,你可以通过名字来获取这些元素的值:
println("The status code is \(http200Status.statusCode)") ```swift
// 输出 "The status code is 200" println("The status code is \(http200Status.statusCode)")
println("The status message is \(http200Status.description)") // 输出 "The status code is 200"
// 输出 "The status message is OK" println("The status message is \(http200Status.description)")
// 输出 "The status message is OK"
```
作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个`(Int, String)`元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考[函数参数与返回值](06_Functions.html#Function_Parameters_and_Return_Values)。 作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个`(Int, String)`元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考[函数参数与返回值](06_Functions.html#Function_Parameters_and_Return_Values)。
> 注意: > 注意:
>
元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组。请参考[类和结构体](09_Classes_and_Structures.html)。 元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组。请参考[类和结构体](09_Classes_and_Structures.html)。
<a name="optionals"></a> <a name="optionals"></a>
@ -449,17 +513,18 @@ _元组tuples_把多个值组合成一个复合值。元组内的值可以
* _没有_值 * _没有_值
> 注意: > 注意:
>
C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C 中的一个特性,一个方法要不返回一个对象要不返回`nil``nil`表示“缺少一个合法的对象”。然而,这只对对象起作用——对于结构体,基本的 C 类型或者枚举类型不起作用。对于这些类型Objective-C 方法一般会返回一个特殊值(比如`NSNotFound`来暗示值缺失。这种方法假设方法的调用者知道并记得对特殊值进行判断。然而Swift 的可选可以让你暗示_任意类型_的值缺失并不需要一个特殊值。 C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C 中的一个特性,一个方法要不返回一个对象要不返回`nil``nil`表示“缺少一个合法的对象”。然而,这只对对象起作用——对于结构体,基本的 C 类型或者枚举类型不起作用。对于这些类型Objective-C 方法一般会返回一个特殊值(比如`NSNotFound`来暗示值缺失。这种方法假设方法的调用者知道并记得对特殊值进行判断。然而Swift 的可选可以让你暗示_任意类型_的值缺失并不需要一个特殊值。
来看一个例子。Swift 的`String`类型有一个叫做`toInt`的方法,作用是将一个`String`值转换成一个`Int`值。然而,并不是所有的字符串都可以转换成一个整数。字符串`"123"`可以被转换成数字`123`,但是字符串`"hello, world"`不行。 来看一个例子。Swift 的`String`类型有一个叫做`toInt`的方法,作用是将一个`String`值转换成一个`Int`值。然而,并不是所有的字符串都可以转换成一个整数。字符串`"123"`可以被转换成数字`123`,但是字符串`"hello, world"`不行。
下面的例子使用`toInt`方法来尝试将一个`String`转换成`Int` 下面的例子使用`toInt`方法来尝试将一个`String`转换成`Int`
let possibleNumber = "123" ```swift
let convertedNumber = possibleNumber.toInt() let possibleNumber = "123"
// convertedNumber 被推测为类型 "Int?" 或者类型 "optional Int" let convertedNumber = possibleNumber.toInt()
// convertedNumber 被推测为类型 "Int?" 或者类型 "optional Int"
```
因为`toInt`方法可能会失败所以它返回一个_可选的optional_`Int`,而不是一个`Int`。一个可选的`Int`被写作`Int?`而不是`Int`。问号暗示包含的值是可选,也就是说可能包含`Int`值也可能不包含值。(不能包含其他任何值比如`Bool`值或者`String`值。只能是`Int`或者什么都没有。) 因为`toInt`方法可能会失败所以它返回一个_可选的optional_`Int`,而不是一个`Int`。一个可选的`Int`被写作`Int?`而不是`Int`。问号暗示包含的值是可选,也就是说可能包含`Int`值也可能不包含值。(不能包含其他任何值比如`Bool`值或者`String`值。只能是`Int`或者什么都没有。)
@ -469,17 +534,18 @@ C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C
当你确定可选_确实_包含值之后你可以在可选的名字后面加一个感叹号`!`来获取值。这个惊叹号表示“我知道这个可选有值请使用它。”这被称为可选值的_强制解析forced unwrapping_ 当你确定可选_确实_包含值之后你可以在可选的名字后面加一个感叹号`!`来获取值。这个惊叹号表示“我知道这个可选有值请使用它。”这被称为可选值的_强制解析forced unwrapping_
if convertedNumber { ```swift
println("\(possibleNumber) has an integer value of \(convertedNumber!)") if convertedNumber {
} else { println("\(possibleNumber) has an integer value of \(convertedNumber!)")
println("\(possibleNumber) could not be converted to an integer") } else {
} println("\(possibleNumber) could not be converted to an integer")
// 输出 "123 has an integer value of 123" }
// 输出 "123 has an integer value of 123"
```
更多关于`if`语句的内容,请参考[控制流](05_Control_Flow.html)。 更多关于`if`语句的内容,请参考[控制流](05_Control_Flow.html)。
> 注意: > 注意:
>
使用`!`来获取一个不存在的可选值会导致运行时错误。使用`!`来强制解析值之前,一定要确定可选包含一个非`nil`的值。 使用`!`来获取一个不存在的可选值会导致运行时错误。使用`!`来强制解析值之前,一定要确定可选包含一个非`nil`的值。
<a name="optional_binding"></a> <a name="optional_binding"></a>
@ -489,18 +555,22 @@ C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C
像下面这样在`if`语句中写一个可选绑定: 像下面这样在`if`语句中写一个可选绑定:
if let constantName = someOptional { ```swift
statements if let constantName = someOptional {
} statements
}
```
你可以像上面这样使用可选绑定来重写`possibleNumber`这个例子: 你可以像上面这样使用可选绑定来重写`possibleNumber`这个例子:
if let actualNumber = possibleNumber.toInt() { ```swift
println("\(possibleNumber) has an integer value of \(actualNumber)") if let actualNumber = possibleNumber.toInt() {
} else { println("\(possibleNumber) has an integer value of \(actualNumber)")
println("\(possibleNumber) could not be converted to an integer") } else {
} println("\(possibleNumber) could not be converted to an integer")
// 输出 "123 has an integer value of 123" }
// 输出 "123 has an integer value of 123"
```
这段代码可以被理解为: 这段代码可以被理解为:
@ -514,22 +584,24 @@ C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C
你可以给可选变量赋值为`nil`来表示它没有值: 你可以给可选变量赋值为`nil`来表示它没有值:
var serverResponseCode: Int? = 404 ```swift
// serverResponseCode 包含一个可选的 Int 404 var serverResponseCode: Int? = 404
serverResponseCode = nil // serverResponseCode 包含一个可选的 Int 值 404
// serverResponseCode 现在不包含值 serverResponseCode = nil
// serverResponseCode 现在不包含值
```
> 注意: > 注意:
>
`nil`不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失的情况,请把它们声明成对应的可选类型。 `nil`不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失的情况,请把它们声明成对应的可选类型。
如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为`nil` 如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为`nil`
var surveyAnswer: String? ```swift
// surveyAnswer 被自动设置为 nil var surveyAnswer: String?
// surveyAnswer 被自动设置为 nil
```
> 注意: > 注意:
>
Swift 的`nil`和 Objective-C 中的`nil`并不一样。在 Objective-C 中,`nil`是一个指向不存在对象的指针。在 Swift 中,`nil`不是指针——它是一个确定的值用来表示值缺失。_任何_类型的可选都可以被设置为`nil`,不只是对象类型。 Swift 的`nil`和 Objective-C 中的`nil`并不一样。在 Objective-C 中,`nil`是一个指向不存在对象的指针。在 Swift 中,`nil`不是指针——它是一个确定的值用来表示值缺失。_任何_类型的可选都可以被设置为`nil`,不只是对象类型。
### 隐式解析可选 ### 隐式解析可选
@ -544,36 +616,42 @@ Swift 的`nil`和 Objective-C 中的`nil`并不一样。在 Objective-C 中,`n
一个隐式解析可选其实就是一个普通的可选,但是可以被当做非可选来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选`String`和隐式解析可选`String`之间的区别: 一个隐式解析可选其实就是一个普通的可选,但是可以被当做非可选来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选`String`和隐式解析可选`String`之间的区别:
let possibleString: String? = "An optional string." ```swift
println(possibleString!) // 需要惊叹号来获取值 let possibleString: String? = "An optional string."
// 输出 "An optional string." println(possibleString!) // 需要惊叹号来获取值
// 输出 "An optional string."
```
let assumedString: String! = "An implicitly unwrapped optional string." ```swift
println(assumedString) // 不需要感叹号 let assumedString: String! = "An implicitly unwrapped optional string."
// 输出 "An implicitly unwrapped optional string." println(assumedString) // 不需要感叹号
// 输出 "An implicitly unwrapped optional string."
```
你可以把隐式解析可选当做一个可以自动解析的可选。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。 你可以把隐式解析可选当做一个可以自动解析的可选。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。
> 注意: > 注意:
>
如果你在隐式解析可选没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选后面加一个惊叹号一样。 如果你在隐式解析可选没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选后面加一个惊叹号一样。
你仍然可以把隐式解析可选当做普通可选来判断它是否包含值: 你仍然可以把隐式解析可选当做普通可选来判断它是否包含值:
if assumedString { ```swift
println(assumedString) if assumedString {
} println(assumedString)
// 输出 "An implicitly unwrapped optional string." }
// 输出 "An implicitly unwrapped optional string."
```
你也可以在可选绑定中使用隐式解析可选来检查并解析它的值: 你也可以在可选绑定中使用隐式解析可选来检查并解析它的值:
if let definiteString = assumedString { ```swift
println(definiteString) if let definiteString = assumedString {
} println(definiteString)
// 输出 "An implicitly unwrapped optional string." }
// 输出 "An implicitly unwrapped optional string."
```
> 注意: > 注意:
>
如果一个变量之后可能变成`nil`的话请不要使用隐式解析可选。如果你需要在变量的生命周期中判断是否是`nil`的话,请使用普通可选类型。 如果一个变量之后可能变成`nil`的话请不要使用隐式解析可选。如果你需要在变量的生命周期中判断是否是`nil`的话,请使用普通可选类型。
<a name="assertions"></a> <a name="assertions"></a>
@ -589,15 +667,19 @@ Swift 的`nil`和 Objective-C 中的`nil`并不一样。在 Objective-C 中,`n
你可以使用全局`assert`函数来写一个断言。向`assert`函数传入一个结果为`true`或者`false`的表达式以及一条信息,当表达式为`false`的时候这条信息会被显示: 你可以使用全局`assert`函数来写一个断言。向`assert`函数传入一个结果为`true`或者`false`的表达式以及一条信息,当表达式为`false`的时候这条信息会被显示:
let age = -3 ```swift
assert(age >= 0, "A person's age cannot be less than zero") let age = -3
// 因为 age < 0所以断言会触发 assert(age >= 0, "A person's age cannot be less than zero")
// 因为 age < 0所以断言会触发
```
在这个例子中,只有`age >= 0`为`true`的时候代码运行才会继续,也就是说,当`age`的值非负的时候。如果`age`的值是负数,就像代码中那样,`age >= 0`为`false`,断言被触发,结束应用。 在这个例子中,只有`age >= 0`为`true`的时候代码运行才会继续,也就是说,当`age`的值非负的时候。如果`age`的值是负数,就像代码中那样,`age >= 0`为`false`,断言被触发,结束应用。
断言信息不能使用字符串插值。断言信息可以省略,就像这样: 断言信息不能使用字符串插值。断言信息可以省略,就像这样:
assert(age >= 0) ```swift
assert(age >= 0)
```
### 何时使用断言 ### 何时使用断言
@ -609,6 +691,6 @@ Swift 的`nil`和 Objective-C 中的`nil`并不一样。在 Objective-C 中,`n
请参考[附属脚本](12_Subscripts.html)和[函数](06_Functions.html)。 请参考[附属脚本](12_Subscripts.html)和[函数](06_Functions.html)。
> 注意: > 注意:
>
断言可能导致你的应用终止运行,所以你应当仔细设计你的代码来让非法条件不会出现。然而,在你的应用发布之前,有时候非法条件可能出现,这时使用断言可以快速发现问题。 断言可能导致你的应用终止运行,所以你应当仔细设计你的代码来让非法条件不会出现。然而,在你的应用发布之前,有时候非法条件可能出现,这时使用断言可以快速发现问题。

View File

@ -1,6 +1,5 @@
> 翻译xielingwang > 翻译xielingwang
> 校对Evilcome
> 校对Evilcome
# 基本运算符 # 基本运算符
----------------- -----------------
@ -49,7 +48,7 @@ a = b
如果赋值的右边是一个多元组,它的元素可以马上被分解多个变量或变量: 如果赋值的右边是一个多元组,它的元素可以马上被分解多个变量或变量:
``` ```swiflt
let (x, y) = (1, 2) let (x, y) = (1, 2)
// 现在 x 等于 1, y 等于 2 // 现在 x 等于 1, y 等于 2
``` ```
@ -105,8 +104,7 @@ let dogCow = dog + cow
求余运算(`a % b`)是计算`b`的多少倍刚刚好可以容入`a`,返回多出来的那部分(余数)。 求余运算(`a % b`)是计算`b`的多少倍刚刚好可以容入`a`,返回多出来的那部分(余数)。
>注意: >注意:
>
求余运算(`%`)在其他语言也叫取模运算。然而严格说来,我们看该运算符对负数的操作结果,"求余"比"取模"更合适些。 求余运算(`%`)在其他语言也叫取模运算。然而严格说来,我们看该运算符对负数的操作结果,"求余"比"取模"更合适些。
我们来谈谈取余是怎么回事,计算`9 % 4`,你先计算出`4`的多少倍会刚好可以容入`9`中: 我们来谈谈取余是怎么回事,计算`9 % 4`,你先计算出`4`的多少倍会刚好可以容入`9`中:
@ -230,8 +228,7 @@ a += 2 // a 现在是 3
表达式`a += 2``a = a + 2`的简写,一个加赋运算就把加法和赋值两件事完成了。 表达式`a += 2``a = a + 2`的简写,一个加赋运算就把加法和赋值两件事完成了。
>注意: >注意:
>
复合赋值运算没有返回值,`let b = a += 2`这类代码是错误。这不同于上面提到的自增和自减运算符。 复合赋值运算没有返回值,`let b = a += 2`这类代码是错误。这不同于上面提到的自增和自减运算符。
在[表达式](../chapter3/04_Expressions.html)章节里有复合运算符的完整列表。 在[表达式](../chapter3/04_Expressions.html)章节里有复合运算符的完整列表。
@ -248,8 +245,7 @@ a += 2 // a 现在是 3
- 大于等于(`a >= b` - 大于等于(`a >= b`
- 小于等于(`a <= b` - 小于等于(`a <= b`
> 注意: > 注意:
>
Swift 也提供恒等`===`和不恒等`!==`这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在[类与结构](09_Classes_and_Structures.html)。 Swift 也提供恒等`===`和不恒等`!==`这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在[类与结构](09_Classes_and_Structures.html)。
每个比较运算都返回了一个标识表达式是否成立的布尔值: 每个比较运算都返回了一个标识表达式是否成立的布尔值:
@ -286,10 +282,9 @@ if name == "world" {
```swift ```swift
if question: { if question: {
answer1 answer1
} } else {
else { answer2
answer2
} }
``` ```
@ -332,7 +327,7 @@ Swift 提供了两个方便表达一个区间的值的运算符。
```swift ```swift
for index in 1...5 { for index in 1...5 {
println("\(index) * 5 = \(index * 5)") println("\(index) * 5 = \(index * 5)")
} }
// 1 * 5 = 5 // 1 * 5 = 5
// 2 * 5 = 10 // 2 * 5 = 10

View File

@ -1,6 +1,5 @@
> 翻译wh1100717 > 翻译wh1100717
> 校对Hawstein
> 校对Hawstein
# 字符串和字符Strings and Characters # 字符串和字符Strings and Characters
----------------- -----------------
@ -31,11 +30,9 @@ Swift 的`String`和`Character`类型提供了一个快速的,兼容 Unicode
Swift 可以在常量、变量、字面量和表达式中进行字符串插值操作,可以轻松创建用于展示、存储和打印的自定义字符串。 Swift 可以在常量、变量、字面量和表达式中进行字符串插值操作,可以轻松创建用于展示、存储和打印的自定义字符串。
> 注意: > 注意:
>
Swift 的`String`类型与 Foundation `NSString`类进行了无缝桥接。如果您利用 Cocoa 或 Cocoa Touch 中的 Foundation 框架进行工作。所有`NSString` API 都可以调用您创建的任意`String`类型的值。除此之外,还可以使用本章介绍的`String`特性。您也可以在任意要求传入`NSString`实例作为参数的 API 中使用`String`类型的值作为替代。 Swift 的`String`类型与 Foundation `NSString`类进行了无缝桥接。如果您利用 Cocoa 或 Cocoa Touch 中的 Foundation 框架进行工作。所有`NSString` API 都可以调用您创建的任意`String`类型的值。除此之外,还可以使用本章介绍的`String`特性。您也可以在任意要求传入`NSString`实例作为参数的 API 中使用`String`类型的值作为替代。
> >更多关于在 Foundation 和 Cocoa 中使用`String`的信息请查看 [Using Swift with Cocoa and Objective-C](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216)。
>更多关于在 Foundation 和 Cocoa 中使用`String`的信息请查看 [Using Swift with Cocoa and Objective-C](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216)。
<a name="string_literals"></a> <a name="string_literals"></a>
## 字符串字面量String Literals ## 字符串字面量String Literals
@ -45,12 +42,11 @@ Swift 的`String`类型与 Foundation `NSString`类进行了无缝桥接。如
字符串字面量可以用于为常量和变量提供初始值。 字符串字面量可以用于为常量和变量提供初始值。
``` ```swift
let someString = "Some string literal value" let someString = "Some string literal value"
``` ```
> 注意: > 注意:
>
`someString`变量通过字符串字面量进行初始化Swift 因此推断该变量为`String`类型。 `someString`变量通过字符串字面量进行初始化Swift 因此推断该变量为`String`类型。
字符串字面量可以包含以下特殊字符: 字符串字面量可以包含以下特殊字符:
@ -64,12 +60,12 @@ let someString = "Some string literal value"
`wiseWords`常量包含了两个转移特殊字符 (双括号) `wiseWords`常量包含了两个转移特殊字符 (双括号)
`dollarSign``blackHeart``sparklingHeart`常量演示了三种不同格式的 Unicode 标量: `dollarSign``blackHeart``sparklingHeart`常量演示了三种不同格式的 Unicode 标量:
``` ```swift
let wiseWords = "\"我是要成为海贼王的男人\" - 路飞" let wiseWords = "\"我是要成为海贼王的男人\" - 路飞"
// "我是要成为海贼王的男人" - 路飞 // "我是要成为海贼王的男人" - 路飞
let dollarSign = "\x24" // $, Unicode 标量 U+0024 let dollarSign = "\x24" // $, Unicode 标量 U+0024
let blackHeart = "\u2665" // ♥, Unicode 标量 U+2665 let blackHeart = "\u2665" // ♥, Unicode 标量 U+2665
let sparklingHeart = "\U0001F496" // 💖, Unicode 标量 U+1F496 let sparklingHeart = "\U0001F496" // 💖, Unicode 标量 U+1F496
``` ```
<a name="initializing_an_empty_string"></a> <a name="initializing_an_empty_string"></a>
@ -78,7 +74,7 @@ let sparklingHeart = "\U0001F496" // 💖, Unicode 标量 U+1F496
为了构造一个很长的字符串,可以创建一个空字符串作为初始值。 为了构造一个很长的字符串,可以创建一个空字符串作为初始值。
可以将空的字符串字面量赋值给变量,也可以初始化一个新的`String`实例: 可以将空的字符串字面量赋值给变量,也可以初始化一个新的`String`实例:
``` ```swift
var emptyString = "" // 空字符串字面量 var emptyString = "" // 空字符串字面量
var anotherEmptyString = String() // 初始化 String 实例 var anotherEmptyString = String() // 初始化 String 实例
// 两个字符串均为空并等价。 // 两个字符串均为空并等价。
@ -86,7 +82,7 @@ var anotherEmptyString = String() // 初始化 String 实例
您可以通过检查其`Boolean`类型的`isEmpty`属性来判断该字符串是否为空: 您可以通过检查其`Boolean`类型的`isEmpty`属性来判断该字符串是否为空:
``` ```swift
if emptyString.isEmpty { if emptyString.isEmpty {
println("什么都没有") println("什么都没有")
} }
@ -98,7 +94,7 @@ if emptyString.isEmpty {
您可以通过将一个特定字符串分配给一个变量来对其进行修改,或者分配给一个常量来保证其不会被修改: 您可以通过将一个特定字符串分配给一个变量来对其进行修改,或者分配给一个常量来保证其不会被修改:
``` ```swift
var variableString = "Horse" var variableString = "Horse"
variableString += " and carriage" variableString += " and carriage"
// variableString 现在为 "Horse and carriage" // variableString 现在为 "Horse and carriage"
@ -107,8 +103,7 @@ constantString += " and another Highlander"
// 这会报告一个编译错误 (compile-time error) - 常量不可以被修改。 // 这会报告一个编译错误 (compile-time error) - 常量不可以被修改。
``` ```
> 注意: > 注意:
>
在 Objective-C 和 Cocoa 中,您通过选择两个不同的类(`NSString``NSMutableString`)来指定该字符串是否可以被修改Swift 中的字符串是否可以修改仅通过定义的是变量还是常量来决定,实现了多种类型可变性操作的统一。 在 Objective-C 和 Cocoa 中,您通过选择两个不同的类(`NSString``NSMutableString`)来指定该字符串是否可以被修改Swift 中的字符串是否可以修改仅通过定义的是变量还是常量来决定,实现了多种类型可变性操作的统一。
<a name="strings_are_value_types"></a> <a name="strings_are_value_types"></a>
@ -119,8 +114,7 @@ Swift 的`String`类型是值类型。
任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作。 任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作。
值类型在 [结构体和枚举是值类型](09_Classes_and_Structures.html#structures_and_enumerations_are_value_types) 中进行了说明。 值类型在 [结构体和枚举是值类型](09_Classes_and_Structures.html#structures_and_enumerations_are_value_types) 中进行了说明。
> 注意: > 注意:
>
与 Cocoa 中的`NSString`不同,当您在 Cocoa 中创建了一个`NSString`实例,并将其传递给一个函数/方法,或者赋值给一个变量,您传递或赋值的是该`NSString`实例的一个引用,除非您特别要求进行值拷贝,否则字符串不会生成新的副本来进行赋值操作。 与 Cocoa 中的`NSString`不同,当您在 Cocoa 中创建了一个`NSString`实例,并将其传递给一个函数/方法,或者赋值给一个变量,您传递或赋值的是该`NSString`实例的一个引用,除非您特别要求进行值拷贝,否则字符串不会生成新的副本来进行赋值操作。
Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字符串的值。 Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字符串的值。
@ -136,7 +130,7 @@ Swift 的`String`类型表示特定序列的`Character`(字符) 类型值的
每一个字符值代表一个 Unicode 字符。 每一个字符值代表一个 Unicode 字符。
您可利用`for-in`循环来遍历字符串中的每一个字符: 您可利用`for-in`循环来遍历字符串中的每一个字符:
``` ```swift
for character in "Dog!🐶" { for character in "Dog!🐶" {
println(character) println(character)
} }
@ -151,7 +145,7 @@ for-in 循环在 [For Loops](05_Control_Flow.html#for_loops) 中进行了详细
另外,通过标明一个`Character`类型注解并通过字符字面量进行赋值,可以建立一个独立的字符常量或变量: 另外,通过标明一个`Character`类型注解并通过字符字面量进行赋值,可以建立一个独立的字符常量或变量:
``` ```swift
let yenSign: Character = "¥" let yenSign: Character = "¥"
``` ```
@ -160,24 +154,22 @@ let yenSign: Character = "¥"
通过调用全局`countElements`函数,并将字符串作为参数进行传递,可以获取该字符串的字符数量。 通过调用全局`countElements`函数,并将字符串作为参数进行传递,可以获取该字符串的字符数量。
``` ```swift
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪" let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
println("unusualMenagerie has \(countElements(unusualMenagerie)) characters") println("unusualMenagerie has \(countElements(unusualMenagerie)) characters")
// 打印输出:"unusualMenagerie has 40 characters" // 打印输出:"unusualMenagerie has 40 characters"
``` ```
> 注意: > 注意:
>
不同的 Unicode 字符以及相同 Unicode 字符的不同表示方式可能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间。因此字符串的长度不得不通过迭代字符串中每一个字符的长度来进行计算。如果您正在处理一个长字符串,需要注意`countElements`函数必须遍历字符串中的字符以精准计算字符串的长度。 不同的 Unicode 字符以及相同 Unicode 字符的不同表示方式可能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间。因此字符串的长度不得不通过迭代字符串中每一个字符的长度来进行计算。如果您正在处理一个长字符串,需要注意`countElements`函数必须遍历字符串中的字符以精准计算字符串的长度。
> > 另外需要注意的是通过`countElements`返回的字符数量并不总是与包含相同字符的`NSString`的`length`属性相同。`NSString`的`length`属性是基于利用 UTF-16 表示的十六位代码单元数字,而不是基于 Unicode 字符。为了解决这个问题,`NSString`的`length`属性在被 Swift 的`String`访问时会成为`utf16count`。
> 另外需要注意的是通过`countElements`返回的字符数量并不总是与包含相同字符的`NSString`的`length`属性相同。`NSString`的`length`属性是基于利用 UTF-16 表示的十六位代码单元数字,而不是基于 Unicode 字符。为了解决这个问题,`NSString`的`length`属性在被 Swift 的`String`访问时会成为`utf16count`。
<a name="concatenating_strings_and_characters"></a> <a name="concatenating_strings_and_characters"></a>
## 连接字符串和字符 (Concatenating Strings and Characters) ## 连接字符串和字符 (Concatenating Strings and Characters)
字符串和字符的值可以通过加法运算符(`+`)相加在一起并创建一个新的字符串值: 字符串和字符的值可以通过加法运算符(`+`)相加在一起并创建一个新的字符串值:
``` ```swift
let string1 = "hello" let string1 = "hello"
let string2 = " there" let string2 = " there"
let character1: Character = "!" let character1: Character = "!"
@ -191,7 +183,7 @@ let characterPlusCharacter = character1 + character2 // 等于 "!?"
您也可以通过加法赋值运算符 (`+=`) 将一个字符串或者字符添加到一个已经存在字符串变量上: 您也可以通过加法赋值运算符 (`+=`) 将一个字符串或者字符添加到一个已经存在字符串变量上:
``` ```swift
var instruction = "look over" var instruction = "look over"
instruction += string2 instruction += string2
// instruction 现在等于 "look over there" // instruction 现在等于 "look over there"
@ -201,8 +193,7 @@ welcome += character1
// welcome 现在等于 "good morning!" // welcome 现在等于 "good morning!"
``` ```
> 注意: > 注意:
>
您不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。 您不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。
<a name="string_interpolation"></a> <a name="string_interpolation"></a>
@ -211,7 +202,7 @@ welcome += character1
字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。 字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。
您插入的字符串字面量的每一项都被包裹在以反斜线为前缀的圆括号中: 您插入的字符串字面量的每一项都被包裹在以反斜线为前缀的圆括号中:
``` ```swift
let multiplier = 3 let multiplier = 3
let message = "\(multiplier) 乘以 2.5 是 \(Double(multiplier) * 2.5)" let message = "\(multiplier) 乘以 2.5 是 \(Double(multiplier) * 2.5)"
// message 是 "3 乘以 2.5 是 7.5" // message 是 "3 乘以 2.5 是 7.5"
@ -224,8 +215,7 @@ let message = "\(multiplier) 乘以 2.5 是 \(Double(multiplier) * 2.5)"
该表达式计算`Double(multiplier) * 2.5`的值并将结果 (7.5) 插入到字符串中。 该表达式计算`Double(multiplier) * 2.5`的值并将结果 (7.5) 插入到字符串中。
在这个例子中,表达式写为`\(Double(multiplier) * 2.5)`并包含在字符串字面量中。 在这个例子中,表达式写为`\(Double(multiplier) * 2.5)`并包含在字符串字面量中。
> 注意: > 注意:
>
插值字符串中写在括号中的表达式不能包含非转义双引号 (`"`) 和反斜杠 (`\`),并且不能包含回车或换行符。 插值字符串中写在括号中的表达式不能包含非转义双引号 (`"`) 和反斜杠 (`\`),并且不能包含回车或换行符。
<a name="comparing_strings"></a> <a name="comparing_strings"></a>
@ -238,7 +228,7 @@ Swift 提供了三种方式来比较字符串的值:字符串相等、前缀
如果两个字符串以同一顺序包含完全相同的字符,则认为两者字符串相等: 如果两个字符串以同一顺序包含完全相同的字符,则认为两者字符串相等:
``` ```swift
let quotation = "我们是一样一样滴." let quotation = "我们是一样一样滴."
let sameQuotation = "我们是一样一样滴." let sameQuotation = "我们是一样一样滴."
if quotation == sameQuotation { if quotation == sameQuotation {
@ -256,7 +246,7 @@ if quotation == sameQuotation {
下面的例子以一个字符串数组表示莎士比亚话剧《罗密欧与朱丽叶》中前两场的场景位置: 下面的例子以一个字符串数组表示莎士比亚话剧《罗密欧与朱丽叶》中前两场的场景位置:
``` ```swift
let romeoAndJuliet = [ let romeoAndJuliet = [
"Act 1 Scene 1: Verona, A public place", "Act 1 Scene 1: Verona, A public place",
"Act 1 Scene 2: Capulet's mansion", "Act 1 Scene 2: Capulet's mansion",
@ -274,7 +264,7 @@ let romeoAndJuliet = [
您可以利用`hasPrefix`方法来计算话剧中第一幕的场景数: 您可以利用`hasPrefix`方法来计算话剧中第一幕的场景数:
``` ```swift
var act1SceneCount = 0 var act1SceneCount = 0
for scene in romeoAndJuliet { for scene in romeoAndJuliet {
if scene.hasPrefix("Act 1 ") { if scene.hasPrefix("Act 1 ") {
@ -287,7 +277,7 @@ println("There are \(act1SceneCount) scenes in Act 1")
相似地,您可以用`hasSuffix`方法来计算发生在不同地方的场景数: 相似地,您可以用`hasSuffix`方法来计算发生在不同地方的场景数:
``` ```swift
var mansionCount = 0 var mansionCount = 0
var cellCount = 0 var cellCount = 0
for scene in romeoAndJuliet { for scene in romeoAndJuliet {
@ -306,7 +296,7 @@ println("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
您可以通过字符串的`uppercaseString``lowercaseString`属性来访问大写/小写版本的字符串。 您可以通过字符串的`uppercaseString``lowercaseString`属性来访问大写/小写版本的字符串。
``` ```swift
let normal = "Could you help me, please?" let normal = "Could you help me, please?"
let shouty = normal.uppercaseString let shouty = normal.uppercaseString
// shouty 值为 "COULD YOU HELP ME, PLEASE?" // shouty 值为 "COULD YOU HELP ME, PLEASE?"
@ -346,7 +336,7 @@ Swift 提供了几种不同的方式来访问字符串的 Unicode 表示。
下面由`D``o``g``!``🐶`(`DOG FACE`Unicode 标量为`U+1F436`)组成的字符串中的每一个字符代表着一种不同的表示: 下面由`D``o``g``!``🐶`(`DOG FACE`Unicode 标量为`U+1F436`)组成的字符串中的每一个字符代表着一种不同的表示:
``` ```swift
let dogString = "Dog!🐶" let dogString = "Dog!🐶"
``` ```
@ -356,7 +346,7 @@ let dogString = "Dog!🐶"
您可以通过遍历字符串的`utf8`属性来访问它的`UTF-8`表示。 您可以通过遍历字符串的`utf8`属性来访问它的`UTF-8`表示。
其为`UTF8View`类型的属性,`UTF8View`是无符号8位 (`UInt8`) 值的集合,每一个`UInt8`值都是一个字符的 UTF-8 表示: 其为`UTF8View`类型的属性,`UTF8View`是无符号8位 (`UInt8`) 值的集合,每一个`UInt8`值都是一个字符的 UTF-8 表示:
``` ```swift
for codeUnit in dogString.utf8 { for codeUnit in dogString.utf8 {
print("\(codeUnit) ") print("\(codeUnit) ")
} }
@ -373,7 +363,7 @@ print("\n")
您可以通过遍历字符串的`utf16`属性来访问它的`UTF-16`表示。 您可以通过遍历字符串的`utf16`属性来访问它的`UTF-16`表示。
其为`UTF16View`类型的属性,`UTF16View`是无符号16位 (`UInt16`) 值的集合,每一个`UInt16`都是一个字符的 UTF-16 表示: 其为`UTF16View`类型的属性,`UTF16View`是无符号16位 (`UInt16`) 值的集合,每一个`UInt16`都是一个字符的 UTF-16 表示:
``` ```swift
for codeUnit in dogString.utf16 { for codeUnit in dogString.utf16 {
print("\(codeUnit) ") print("\(codeUnit) ")
} }
@ -395,7 +385,7 @@ print("\n")
每一个`UnicodeScalar`拥有一个值属性可以返回对应的21位数值`UInt32`来表示。 每一个`UnicodeScalar`拥有一个值属性可以返回对应的21位数值`UInt32`来表示。
``` ```swift
for scalar in dogString.unicodeScalars { for scalar in dogString.unicodeScalars {
print("\(scalar.value) ") print("\(scalar.value) ")
} }
@ -409,7 +399,7 @@ print("\n")
作为查询字符值属性的一种替代方法,每个`UnicodeScalar`值也可以用来构建一个新的字符串值,比如在字符串插值中使用: 作为查询字符值属性的一种替代方法,每个`UnicodeScalar`值也可以用来构建一个新的字符串值,比如在字符串插值中使用:
``` ```swift
for scalar in dogString.unicodeScalars { for scalar in dogString.unicodeScalars {
println("\(scalar) ") println("\(scalar) ")
} }
@ -419,4 +409,3 @@ for scalar in dogString.unicodeScalars {
// ! // !
// 🐶 // 🐶
``` ```

View File

@ -1,6 +1,5 @@
> 翻译zqp > 翻译zqp
> 校对shinyzhu
> 校对shinyzhu
# 集合类型 (Collection Types) # 集合类型 (Collection Types)
----------------- -----------------
@ -15,8 +14,7 @@ Swift 语言提供经典的数组和字典两种集合类型来存储集合数
Swift 语言里的数组和字典中存储的数据值类型必须明确。 这意味着我们不能把不正确的数据类型插入其中。 同时这也说明我们完全可以对获取出的值类型非常自信。 Swift 对显式类型集合的使用确保了我们的代码对工作所需要的类型非常清楚,也让我们在开发中可以早早地找到任何的类型不匹配错误。 Swift 语言里的数组和字典中存储的数据值类型必须明确。 这意味着我们不能把不正确的数据类型插入其中。 同时这也说明我们完全可以对获取出的值类型非常自信。 Swift 对显式类型集合的使用确保了我们的代码对工作所需要的类型非常清楚,也让我们在开发中可以早早地找到任何的类型不匹配错误。
> 注意: > 注意:
>
Swift 的数组结构在被声明成常量和变量或者被传入函数与方法中时会相对于其他类型展现出不同的特性。 获取更多信息请参见[集合的可变性](#mutability_of_collections)与[集合在赋值和复制中的行为](09_Classes_and_Structures.html#assignment_and_copy_behavior_for_collection_types)章节。 Swift 的数组结构在被声明成常量和变量或者被传入函数与方法中时会相对于其他类型展现出不同的特性。 获取更多信息请参见[集合的可变性](#mutability_of_collections)与[集合在赋值和复制中的行为](09_Classes_and_Structures.html#assignment_and_copy_behavior_for_collection_types)章节。
<a name="arrays"></a> <a name="arrays"></a>
@ -39,20 +37,23 @@ Swift 数组对存储数据有具体要求。 不同于 Objective-C 的`NSArray`
下面这个例子创建了一个叫做`shoppingList`并且存储字符串的数组: 下面这个例子创建了一个叫做`shoppingList`并且存储字符串的数组:
var shoppingList: String[] = ["Eggs", "Milk"] ```swift
// shoppingList 已经被构造并且拥有两个初始项。 var shoppingList: String[] = ["Eggs", "Milk"]
// shoppingList 已经被构造并且拥有两个初始项。
```
`shoppingList`变量被声明为“字符串值类型的数组“,记作`String[]`。 因为这个数组被规定只有`String`一种数据结构,所以只有`String`类型可以在其中被存取。 在这里,`shoppinglist`数组由两个`String`值(`"Eggs"``"Milk"`)构造,并且由字面语句定义。 `shoppingList`变量被声明为“字符串值类型的数组“,记作`String[]`。 因为这个数组被规定只有`String`一种数据结构,所以只有`String`类型可以在其中被存取。 在这里,`shoppinglist`数组由两个`String`值(`"Eggs"``"Milk"`)构造,并且由字面语句定义。
> 注意: > 注意:
> > `Shoppinglist`数组被声明为变量(`var`关键字创建)而不是常量(`let`创建)是因为以后可能会有更多的数据项被插入其中。
> `Shoppinglist`数组被声明为变量(`var`关键字创建)而不是常量(`let`创建)是因为以后可能会有更多的数据项被插入其中。
在这个例子中,字面语句仅仅包含两个`String`值。匹配了该数组的变量声明(只能包含`String`的数组),所以这个字面语句的分配过程就是允许用两个初始项来构造`shoppinglist` 在这个例子中,字面语句仅仅包含两个`String`值。匹配了该数组的变量声明(只能包含`String`的数组),所以这个字面语句的分配过程就是允许用两个初始项来构造`shoppinglist`
由于 Swift 的类型推断机制,当我们用字面语句构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。 `shoppinglist`的构造也可以这样写: 由于 Swift 的类型推断机制,当我们用字面语句构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。 `shoppinglist`的构造也可以这样写:
var shoppingList = ["Eggs", "Milk"] ```swift
var shoppingList = ["Eggs", "Milk"]
```
因为所有字面语句中的值都是相同的类型Swift 可以推断出`String[]``shoppinglist`中变量的正确类型。 因为所有字面语句中的值都是相同的类型Swift 可以推断出`String[]``shoppinglist`中变量的正确类型。
@ -62,105 +63,132 @@ Swift 数组对存储数据有具体要求。 不同于 Objective-C 的`NSArray`
我们可以通过数组的方法和属性来访问和修改数组,或者下标语法。 我们可以通过数组的方法和属性来访问和修改数组,或者下标语法。
还可以使用数组的只读属性`count`来获取数组中的数据项数量。 还可以使用数组的只读属性`count`来获取数组中的数据项数量。
println("The shopping list contains \(shoppingList.count) items.") ```swift
// 输出"The shopping list contains 2 items."这个数组有2个项 println("The shopping list contains \(shoppingList.count) items.")
// 输出"The shopping list contains 2 items."这个数组有2个项
```
使用布尔项`isEmpty`来作为检查`count`属性的值是否为 0 的捷径。 使用布尔项`isEmpty`来作为检查`count`属性的值是否为 0 的捷径。
if shoppingList.isEmpty { ```swift
println("The shopping list is empty.") if shoppingList.isEmpty {
} else { println("The shopping list is empty.")
println("The shopping list is not empty.") } else {
} println("The shopping list is not empty.")
// 打印 "The shopping list is not empty."shoppinglist不是空的 }
// 打印 "The shopping list is not empty."shoppinglist不是空的
```
也可以使用`append`方法在数组后面添加新的数据项: 也可以使用`append`方法在数组后面添加新的数据项:
shoppingList.append("Flour") ```swift
// shoppingList 现在有3个数据项有人在摊煎饼 shoppingList.append("Flour")
// shoppingList 现在有3个数据项有人在摊煎饼
```
除此之外,使用加法赋值运算符(`+=`)也可以直接在数组后面添加数据项: 除此之外,使用加法赋值运算符(`+=`)也可以直接在数组后面添加数据项:
shoppingList += "Baking Powder" ```swift
// shoppingList 现在有四项了 shoppingList += "Baking Powder"
// shoppingList 现在有四项了
```
我们也可以使用加法赋值运算符(`+=`)直接添加拥有相同类型数据的数组。 我们也可以使用加法赋值运算符(`+=`)直接添加拥有相同类型数据的数组。
shoppingList += ["Chocolate Spread", "Cheese", "Butter"] ```swift
// shoppingList 现在有7项了 shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList 现在有7项了
```
可以直接使用下标语法来获取数组中的数据项,把我们需要的数据项的索引值放在直接放在数组名称的方括号中: 可以直接使用下标语法来获取数组中的数据项,把我们需要的数据项的索引值放在直接放在数组名称的方括号中:
var firstItem = shoppingList[0] ```swift
// 第一项是 "Eggs" var firstItem = shoppingList[0]
// 第一项是 "Eggs"
```
注意第一项在数组中的索引值是`0`而不是`1`。 Swift 中的数组索引总是从零开始。 注意第一项在数组中的索引值是`0`而不是`1`。 Swift 中的数组索引总是从零开始。
我们也可以用下标来改变某个已有索引值对应的数据值: 我们也可以用下标来改变某个已有索引值对应的数据值:
shoppingList[0] = "Six eggs" ```swift
// 其中的第一项现在是 "Six eggs" 而不是 "Eggs" shoppingList[0] = "Six eggs"
// 其中的第一项现在是 "Six eggs" 而不是 "Eggs"
```
还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把`"Chocolate Spread"``"Cheese"`,和`"Butter"`替换为`"Bananas"``"Apples"` 还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把`"Chocolate Spread"``"Cheese"`,和`"Butter"`替换为`"Bananas"``"Apples"`
shoppingList[4...6] = ["Bananas", "Apples"] ```swift
// shoppingList 现在有六项 shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList 现在有六项
```
> 注意: > 注意:
> >我们不能使用下标语法在数组尾部添加新项。如果我们试着用这种方法对索引越界的数据进行检索或者设置新值的操作,我们会引发一个运行期错误。我们可以使用索引值和数组的`count`属性进行比较来在使用某个索引之前先检验是否有效。除了当`count`等于 0 时(说明这是个空数组),最大索引值一直是`count - 1`,因为数组都是零起索引。
>我们不能使用下标语法在数组尾部添加新项。如果我们试着用这种方法对索引越界的数据进行检索或者设置新值的操作,我们会引发一个运行期错误。我们可以使用索引值和数组的`count`属性进行比较来在使用某个索引之前先检验是否有效。除了当`count`等于 0 时(说明这是个空数组),最大索引值一直是`count - 1`,因为数组都是零起索引。
调用数组的`insert(atIndex:)`方法来在某个具体索引值之前添加数据项: 调用数组的`insert(atIndex:)`方法来在某个具体索引值之前添加数据项:
shoppingList.insert("Maple Syrup", atIndex: 0) ```swift
// shoppingList 现在有7项 shoppingList.insert("Maple Syrup", atIndex: 0)
// "Maple Syrup" 现在是这个列表中的第一项 // shoppingList 现在有7项
// "Maple Syrup" 现在是这个列表中的第一项
```
这次`insert`函数调用把值为`"Maple Syrup"`的新数据项插入列表的最开始位置,并且使用`0`作为索引值。 这次`insert`函数调用把值为`"Maple Syrup"`的新数据项插入列表的最开始位置,并且使用`0`作为索引值。
类似的我们可以使用`removeAtIndex`方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(我们不需要的时候就可以无视它): 类似的我们可以使用`removeAtIndex`方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(我们不需要的时候就可以无视它):
let mapleSyrup = shoppingList.removeAtIndex(0) ```swift
//索引值为0的数据项被移除 let mapleSyrup = shoppingList.removeAtIndex(0)
// shoppingList 现在只有6项而且不包括Maple Syrup // 索引值为0的数据项被移除
// mapleSyrup常量的值等于被移除数据项的值 "Maple Syrup" // shoppingList 现在只有6项而且不包括Maple Syrup
// mapleSyrup常量的值等于被移除数据项的值 "Maple Syrup"
```
数据项被移除后数组中的空出项会被自动填补,所以现在索引值为`0`的数据项的值再次等于`"Six eggs"`: 数据项被移除后数组中的空出项会被自动填补,所以现在索引值为`0`的数据项的值再次等于`"Six eggs"`:
firstItem = shoppingList[0] ```swift
// firstItem 现在等于 "Six eggs" firstItem = shoppingList[0]
// firstItem 现在等于 "Six eggs"
```
如果我们只想把数组中的最后一项移除,可以使用`removeLast`方法而不是`removeAtIndex`方法来避免我们需要获取数组的`count`属性。就像后者一样,前者也会返回被移除的数据项: 如果我们只想把数组中的最后一项移除,可以使用`removeLast`方法而不是`removeAtIndex`方法来避免我们需要获取数组的`count`属性。就像后者一样,前者也会返回被移除的数据项:
let apples = shoppingList.removeLast() ```swift
// 数组的最后一项被移除了 let apples = shoppingList.removeLast()
// shoppingList现在只有5项不包括cheese // 数组的最后一项被移除了
// apples 常量的值现在等于"Apples" 字符串 // shoppingList现在只有5项不包括cheese
// apples 常量的值现在等于"Apples" 字符串
```
<a name="iterating_over_an_array"></a> <a name="iterating_over_an_array"></a>
### 数组的遍历 ### 数组的遍历
我们可以使用`for-in`循环来遍历所有数组中的数据项: 我们可以使用`for-in`循环来遍历所有数组中的数据项:
for item in shoppingList { ```swift
println(item) for item in shoppingList {
} println(item)
// Six eggs }
// Milk // Six eggs
// Flour // Milk
// Baking Powder // Flour
// Bananas // Baking Powder
// Bananas
```
如果我们同时需要每个数据项的值和索引值,可以使用全局`enumerate`函数来进行数组遍历。`enumerate`返回一个由每一个数据项索引值和数据值组成的键值对组。我们可以把这个键值对组分解成临时常量或者变量来进行遍历: 如果我们同时需要每个数据项的值和索引值,可以使用全局`enumerate`函数来进行数组遍历。`enumerate`返回一个由每一个数据项索引值和数据值组成的键值对组。我们可以把这个键值对组分解成临时常量或者变量来进行遍历:
for (index, value) in enumerate(shoppingList) { ```swift
println("Item \(index + 1): \(value)") for (index, value) in enumerate(shoppingList) {
} println("Item \(index + 1): \(value)")
// Item 1: Six eggs }
// Item 2: Milk // Item 1: Six eggs
// Item 3: Flour // Item 2: Milk
// Item 4: Baking Powder // Item 3: Flour
// Item 5: Bananas // Item 4: Baking Powder
// Item 5: Bananas
```
更多关于`for-in`循环的介绍请参见[for 循环](05_Control_Flow.html#for_loops)。 更多关于`for-in`循环的介绍请参见[for 循环](05_Control_Flow.html#for_loops)。
@ -169,33 +197,43 @@ Swift 数组对存储数据有具体要求。 不同于 Objective-C 的`NSArray`
我们可以使用构造语法来创建一个由特定数据类型构成的空数组: 我们可以使用构造语法来创建一个由特定数据类型构成的空数组:
var someInts = Int[]() ```swift
println("someInts is of type Int[] with \(someInts.count) items。") var someInts = Int[]()
// 打印 "someInts is of type Int[] with 0 items。"someInts是0数据项的Int[]数组) println("someInts is of type Int[] with \(someInts.count) items。")
// 打印 "someInts is of type Int[] with 0 items。"someInts是0数据项的Int[]数组)
```
注意`someInts`被设置为一个`Int[]`构造函数的输出所以它的变量类型被定义为`Int[]` 注意`someInts`被设置为一个`Int[]`构造函数的输出所以它的变量类型被定义为`Int[]`
除此之外,如果代码上下文中提供了类型信息, 例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:`[]`(一对空方括号): 除此之外,如果代码上下文中提供了类型信息, 例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:`[]`(一对空方括号):
someInts.append(3) ```swift
// someInts 现在包含一个INT值 someInts.append(3)
someInts = [] // someInts 现在包含一个INT值
// someInts 现在是空数组但是仍然是Int[]类型的。 someInts = []
// someInts 现在是空数组但是仍然是Int[]类型的。
```
Swift 中的`Array`类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量(`count`)和适当类型的初始值(`repeatedValue`)传入数组构造函数: Swift 中的`Array`类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量(`count`)和适当类型的初始值(`repeatedValue`)传入数组构造函数:
var threeDoubles = Double[](count: 3, repeatedValue:0.0) ```swift
// threeDoubles 是一种 Double[]数组, 等于 [0.0, 0.0, 0.0] var threeDoubles = Double[](count: 3, repeatedValue:0.0)
// threeDoubles 是一种 Double[]数组, 等于 [0.0, 0.0, 0.0]
```
因为类型推断的存在,我们使用这种构造方法的时候不需要特别指定数组中存储的数据类型,因为类型可以从默认值推断出来: 因为类型推断的存在,我们使用这种构造方法的时候不需要特别指定数组中存储的数据类型,因为类型可以从默认值推断出来:
var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5) ```swift
// anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5] var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5)
// anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5]
```
最后,我们可以使用加法操作符(`+`)来组合两种已存在的相同类型数组。新数组的数据类型会被从两个数组的数据类型中推断出来: 最后,我们可以使用加法操作符(`+`)来组合两种已存在的相同类型数组。新数组的数据类型会被从两个数组的数据类型中推断出来:
var sixDoubles = threeDoubles + anotherThreeDoubles ```swift
// sixDoubles 被推断为 Double[], 等于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5] var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles 被推断为 Double[], 等于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
```
<a name="dictionaries"></a> <a name="dictionaries"></a>
## 字典 ## 字典
@ -215,17 +253,20 @@ Swift 的字典使用`Dictionary<KeyType, ValueType>`定义,其中`KeyType`是
一个键值对是一个`key`和一个`value`的结合体。在字典字面语句中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含并且由逗号分割: 一个键值对是一个`key`和一个`value`的结合体。在字典字面语句中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含并且由逗号分割:
[key 1: value 1, key 2: value 2, key 3: value 3] ```swift
[key 1: value 1, key 2: value 2, key 3: value 3]
```
下面的例子创建了一个存储国际机场名称的字典。在这个字典中键是三个字母的国际航空运输相关代码,值是机场名称: 下面的例子创建了一个存储国际机场名称的字典。在这个字典中键是三个字母的国际航空运输相关代码,值是机场名称:
var airports: Dictionary<String, String> = ["TYO": "Tokyo", "DUB": "Dublin"] ```swift
var airports: Dictionary<String, String> = ["TYO": "Tokyo", "DUB": "Dublin"]
```
`airports`字典被定义为一种`Dictionary<String, String>`,它意味着这个字典的键和值都是`String`类型。 `airports`字典被定义为一种`Dictionary<String, String>`,它意味着这个字典的键和值都是`String`类型。
> 注意: > 注意:
> > `airports`字典被声明为变量(用`var`关键字)而不是常量(`let`关键字)因为后来更多的机场信息会被添加到这个示例字典中。
> `airports`字典被声明为变量(用`var`关键字)而不是常量(`let`关键字)因为后来更多的机场信息会被添加到这个示例字典中。
`airports`字典使用字典字面语句初始化,包含两个键值对。第一对的键是`TYO`,值是`Tokyo`。第二对的键是`DUB`,值是`Dublin` `airports`字典使用字典字面语句初始化,包含两个键值对。第一对的键是`TYO`,值是`Tokyo`。第二对的键是`DUB`,值是`Dublin`
@ -233,7 +274,9 @@ Swift 的字典使用`Dictionary<KeyType, ValueType>`定义,其中`KeyType`是
和数组一样,如果我们使用字面语句构造字典就不用把类型定义清楚。`airports`的也可以用这种方法简短定义: 和数组一样,如果我们使用字面语句构造字典就不用把类型定义清楚。`airports`的也可以用这种方法简短定义:
var airports = ["TYO": "Tokyo", "DUB": "Dublin"] ```swift
var airports = ["TYO": "Tokyo", "DUB": "Dublin"]
```
因为这个语句中所有的键和值都分别是相同的数据类型Swift 可以推断出`Dictionary<String, String>``airports`字典的正确类型。 因为这个语句中所有的键和值都分别是相同的数据类型Swift 可以推断出`Dictionary<String, String>``airports`字典的正确类型。
@ -242,111 +285,137 @@ Swift 的字典使用`Dictionary<KeyType, ValueType>`定义,其中`KeyType`是
我们可以通过字典的方法和属性来读取和修改字典,或者使用下标语法。和数组一样,我们可以通过字典的只读属性`count`来获取某个字典的数据项数量: 我们可以通过字典的方法和属性来读取和修改字典,或者使用下标语法。和数组一样,我们可以通过字典的只读属性`count`来获取某个字典的数据项数量:
println("The dictionary of airports contains \(airports.count) items.") ```swift
// 打印 "The dictionary of airports contains 2 items."(这个字典有两个数据项) println("The dictionary of airports contains \(airports.count) items.")
// 打印 "The dictionary of airports contains 2 items."(这个字典有两个数据项)
```
我们也可以在字典中使用下标语法来添加新的数据项。可以使用一个合适类型的 key 作为下标索引,并且分配新的合适类型的值: 我们也可以在字典中使用下标语法来添加新的数据项。可以使用一个合适类型的 key 作为下标索引,并且分配新的合适类型的值:
airports["LHR"] = "London" ```swift
// airports 字典现在有三个数据项 airports["LHR"] = "London"
// airports 字典现在有三个数据项
```
我们也可以使用下标语法来改变特定键对应的值: 我们也可以使用下标语法来改变特定键对应的值:
airports["LHR"] = "London Heathrow" ```swift
// "LHR"对应的值 被改为 "London Heathrow airports["LHR"] = "London Heathrow"
// "LHR"对应的值 被改为 "London Heathrow
```
作为另一种下标方法,字典的`updateValue(forKey:)`方法可以设置或者更新特定键对应的值。就像上面所示的示例,`updateValue(forKey:)`方法在这个键不存在对应值的时候设置值或者在存在时更新已存在的值。和上面的下标方法不一样,这个方法返回更新值之前的原值。这样方便我们检查更新是否成功。 作为另一种下标方法,字典的`updateValue(forKey:)`方法可以设置或者更新特定键对应的值。就像上面所示的示例,`updateValue(forKey:)`方法在这个键不存在对应值的时候设置值或者在存在时更新已存在的值。和上面的下标方法不一样,这个方法返回更新值之前的原值。这样方便我们检查更新是否成功。
`updateValue(forKey:)`函数会返回包含一个字典值类型的可选值。举例来说:对于存储`String`值的字典,这个函数会返回一个`String?`或者“可选 `String`”类型的值。如果值存在,则这个可选值值等于被替换的值,否则将会是`nil` `updateValue(forKey:)`函数会返回包含一个字典值类型的可选值。举例来说:对于存储`String`值的字典,这个函数会返回一个`String?`或者“可选 `String`”类型的值。如果值存在,则这个可选值值等于被替换的值,否则将会是`nil`
if let oldValue = airports.updateValue("Dublin Internation", forKey: "DUB") { ```swift
println("The old value for DUB was \(oldValue).") if let oldValue = airports.updateValue("Dublin Internation", forKey: "DUB") {
} println("The old value for DUB was \(oldValue).")
// 输出 "The old value for DUB was Dublin."DUB原值是dublin }
// 输出 "The old value for DUB was Dublin."DUB原值是dublin
```
我们也可以使用下标语法来在字典中检索特定键对应的值。由于使用一个没有值的键这种情况是有可能发生的,可选类型返回这个键存在的相关值,否则就返回`nil` 我们也可以使用下标语法来在字典中检索特定键对应的值。由于使用一个没有值的键这种情况是有可能发生的,可选类型返回这个键存在的相关值,否则就返回`nil`
if let airportName = airports["DUB"] { ```swift
println("The name of the airport is \(airportName).") if let airportName = airports["DUB"] {
} else { println("The name of the airport is \(airportName).")
println("That airport is not in the airports dictionary.") } else {
} println("That airport is not in the airports dictionary.")
// 打印 "The name of the airport is Dublin Internation."(机场的名字是都柏林国际) }
// 打印 "The name of the airport is Dublin Internation."(机场的名字是都柏林国际)
```
我们还可以使用下标语法来通过给某个键的对应值赋值为`nil`来从字典里移除一个键值对: 我们还可以使用下标语法来通过给某个键的对应值赋值为`nil`来从字典里移除一个键值对:
airports["APL"] = "Apple Internation" ```swift
// "Apple Internation"不是真的 APL机场, 删除它 airports["APL"] = "Apple Internation"
airports["APL"] = nil // "Apple Internation"不是真的 APL机场, 删除它
// APL现在被移除了 airports["APL"] = nil
// APL现在被移除了
```
另外,`removeValueForKey`方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的value或者在没有值的情况下返回`nil` 另外,`removeValueForKey`方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的value或者在没有值的情况下返回`nil`
if let removedValue = airports.removeValueForKey("DUB") { ```swift
println("The removed airport's name is \(removedValue).") if let removedValue = airports.removeValueForKey("DUB") {
} else { println("The removed airport's name is \(removedValue).")
println("The airports dictionary does not contain a value for DUB.") } else {
} println("The airports dictionary does not contain a value for DUB.")
// prints "The removed airport's name is Dublin International." }
// prints "The removed airport's name is Dublin International."
```
<a name="iterating_over_a_dictionary"></a> <a name="iterating_over_a_dictionary"></a>
### 字典遍历 ### 字典遍历
我们可以使用`for-in`循环来遍历某个字典中的键值对。每一个字典中的数据项都由`(key, value)`元组形式返回,并且我们可以使用暂时性常量或者变量来分解这些元组: 我们可以使用`for-in`循环来遍历某个字典中的键值对。每一个字典中的数据项都由`(key, value)`元组形式返回,并且我们可以使用暂时性常量或者变量来分解这些元组:
for (airportCode, airportName) in airports { ```swift
println("\(airportCode): \(airportName)") for (airportCode, airportName) in airports {
} println("\(airportCode): \(airportName)")
// TYO: Tokyo }
// LHR: London Heathrow // TYO: Tokyo
// LHR: London Heathrow
```
`for-in`循环请参见[For 循环](05_Control_Flow.html#for_loops)。 `for-in`循环请参见[For 循环](05_Control_Flow.html#for_loops)。
我们也可以通过访问他的`keys`或者`values`属性(都是可遍历集合)检索一个字典的键或者值: 我们也可以通过访问他的`keys`或者`values`属性(都是可遍历集合)检索一个字典的键或者值:
for airportCode in airports.keys { ```swift
println("Airport code: \(airportCode)") for airportCode in airports.keys {
} println("Airport code: \(airportCode)")
// Airport code: TYO }
// Airport code: LHR // Airport code: TYO
// Airport code: LHR
```
for airportName in airports.values { ```swift
println("Airport name: \(airportName)") for airportName in airports.values {
} println("Airport name: \(airportName)")
// Airport name: Tokyo }
// Airport name: London Heathrow // Airport name: Tokyo
// Airport name: London Heathrow
```
如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受`Array`实例 API 的参数,可以直接使用`keys`或者`values`属性直接构造一个新数组: 如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受`Array`实例 API 的参数,可以直接使用`keys`或者`values`属性直接构造一个新数组:
let airportCodes = Array(airports.keys) ```swift
// airportCodes is ["TYO", "LHR"] let airportCodes = Array(airports.keys)
// airportCodes is ["TYO", "LHR"]
```
let airportNames = Array(airports.values) ```swift
// airportNames is ["Tokyo", "London Heathrow"] let airportNames = Array(airports.values)
// airportNames is ["Tokyo", "London Heathrow"]
```
> 注意: > 注意:
> > Swift 的字典类型是无序集合类型。其中字典键,值,键值对在遍历的时候会重新排列,而且其中顺序是不固定的。
> Swift 的字典类型是无序集合类型。其中字典键,值,键值对在遍历的时候会重新排列,而且其中顺序是不固定的。
<a name="creating_an_empty_dictionary"></a> <a name="creating_an_empty_dictionary"></a>
### 创建一个空字典 ### 创建一个空字典
我们可以像数组一样使用构造语法创建一个空字典: 我们可以像数组一样使用构造语法创建一个空字典:
var namesOfIntegers = Dictionary<Int, String>() ```swift
// namesOfIntegers 是一个空的 Dictionary<Int, String> var namesOfIntegers = Dictionary<Int, String>()
// namesOfIntegers 是一个空的 Dictionary<Int, String>
```
这个例子创建了一个`Int, String`类型的空字典来储存英语对整数的命名。它的键是`Int`型,值是`String`型。 这个例子创建了一个`Int, String`类型的空字典来储存英语对整数的命名。它的键是`Int`型,值是`String`型。
如果上下文已经提供了信息类型,我们可以使用空字典字面语句来创建一个空字典,记作`[:]`(中括号中放一个冒号): 如果上下文已经提供了信息类型,我们可以使用空字典字面语句来创建一个空字典,记作`[:]`(中括号中放一个冒号):
namesOfIntegers[16] = "sixteen" ```swift
// namesOfIntegers 现在包含一个键值对 namesOfIntegers[16] = "sixteen"
namesOfIntegers = [:] // namesOfIntegers 现在包含一个键值对
// namesOfIntegers 又成为了一个 Int, String类型的空字典 namesOfIntegers = [:]
// namesOfIntegers 又成为了一个 Int, String类型的空字典
```
> 注意: > 注意:
> > 在后台Swift 的数组和字典都是由泛型集合来实现的,想了解更多泛型和集合信息请参见[泛型](22_Generics.html)。
> 在后台Swift 的数组和字典都是由泛型集合来实现的,想了解更多泛型和集合信息请参见[泛型](22_Generics.html)。
<a name="mutability_of_collections"></a> <a name="mutability_of_collections"></a>
## 集合的可变性 ## 集合的可变性
@ -358,6 +427,6 @@ Swift 的字典使用`Dictionary<KeyType, ValueType>`定义,其中`KeyType`是
Swift 数组的可变性行为同时影响了数组实例如何被分配和修改,想获取更多信息,请参见[集合在赋值和复制中的行为](09_Classes_and_Structures.html#assignment_and_copy_behavior_for_collection_types)。 Swift 数组的可变性行为同时影响了数组实例如何被分配和修改,想获取更多信息,请参见[集合在赋值和复制中的行为](09_Classes_and_Structures.html#assignment_and_copy_behavior_for_collection_types)。
> 注意: > 注意:
> > 在我们不需要改变数组大小的时候创建不可变数组是很好的习惯。如此 Swift 编译器可以优化我们创建的集合。
> 在我们不需要改变数组大小的时候创建不可变数组是很好的习惯。如此 Swift 编译器可以优化我们创建的集合。

View File

@ -1,6 +1,5 @@
> 翻译vclwei, coverxit, NicePiao > 翻译vclwei, coverxit, NicePiao
> 校对coverxit, stanzhai
> 校对coverxit
# 控制流 # 控制流
----------------- -----------------
@ -24,7 +23,6 @@ Swift 的`switch`语句比 C 语言中更加强大。在 C 语言中,如果某
`for`循环用来按照指定的次数多次执行一系列语句。Swift 提供两种`for`循环形式: `for`循环用来按照指定的次数多次执行一系列语句。Swift 提供两种`for`循环形式:
* `for-in`用来遍历一个区间range序列sequence集合collection系列progression里面所有的元素执行一系列语句。 * `for-in`用来遍历一个区间range序列sequence集合collection系列progression里面所有的元素执行一系列语句。
* for条件递增`for-condition-increment`)语句,用来重复执行一系列语句直到达成特定条件达成,一般通过在每次循环完成后增加计数器的值来实现。 * for条件递增`for-condition-increment`)语句,用来重复执行一系列语句直到达成特定条件达成,一般通过在每次循环完成后增加计数器的值来实现。
<a name="for_in"></a> <a name="for_in"></a>
@ -49,8 +47,7 @@ for index in 1...5 {
上面的例子中,`index`是一个每次循环遍历开始时被自动赋值的常量。这种情况下,`index`在使用前不需要声明,只需要将它包含在循环的声明中,就可以对其进行隐式声明,而无需使用`let`关键字声明。 上面的例子中,`index`是一个每次循环遍历开始时被自动赋值的常量。这种情况下,`index`在使用前不需要声明,只需要将它包含在循环的声明中,就可以对其进行隐式声明,而无需使用`let`关键字声明。
>注意: >注意:
>
`index`常量只存在于循环的生命周期里。如果你想在循环完成后访问`index`的值,又或者想让`index`成为一个变量而不是常量,你必须在循环之前自己进行声明。 `index`常量只存在于循环的生命周期里。如果你想在循环完成后访问`index`的值,又或者想让`index`成为一个变量而不是常量,你必须在循环之前自己进行声明。
如果你不需要知道区间内每一项的值,你可以使用下划线(`_`)替代变量名来忽略对值的访问: 如果你不需要知道区间内每一项的值,你可以使用下划线(`_`)替代变量名来忽略对值的访问:
@ -124,11 +121,9 @@ for var index = 0; index < 3; ++index {
下面是一般情况下这种循环方式的格式: 下面是一般情况下这种循环方式的格式:
```swift > for `initialization`; `condition`; `increment` {
for `initialization`; `condition`; `increment` { > `statements`
`statements` > }
}
```
和 C 语言中一样,分号将循环的定义分为 3 个部分不同的是Swift 不需要使用圆括号将“initialization; condition; increment”包括起来。 和 C 语言中一样,分号将循环的定义分为 3 个部分不同的是Swift 不需要使用圆括号将“initialization; condition; increment”包括起来。
@ -141,13 +136,11 @@ for `initialization`; `condition`; `increment` {
上述描述和循环格式等同于: 上述描述和循环格式等同于:
```swift > `initialization`
`initialization` > while `condition` {
while `condition` { > `statements`
`statements` > `increment`
`increment` > }
}
```
在初始化表达式中声明的常量和变量(比如`var index = 0`)只在`for`循环的生命周期里有效。如果想在循环结束后访问`index`的值,你必须要在循环生命周期开始前声明`index` 在初始化表达式中声明的常量和变量(比如`var index = 0`)只在`for`循环的生命周期里有效。如果想在循环结束后访问`index`的值,你必须要在循环生命周期开始前声明`index`
@ -171,7 +164,6 @@ println("The loop statements were executed \(index) times")
`while`循环运行一系列语句直到条件变成`false`。这类循环适合使用在第一次迭代前迭代次数未知的情况下。Swift 提供两种`while`循环形式: `while`循环运行一系列语句直到条件变成`false`。这类循环适合使用在第一次迭代前迭代次数未知的情况下。Swift 提供两种`while`循环形式:
* `while`循环,每次在循环开始时计算条件是否符合; * `while`循环,每次在循环开始时计算条件是否符合;
* `do-while`循环,每次在循环结束时计算条件是否符合。 * `do-while`循环,每次在循环结束时计算条件是否符合。
<a name="while"></a> <a name="while"></a>
@ -181,11 +173,9 @@ println("The loop statements were executed \(index) times")
下面是一般情况下 `while` 循环格式: 下面是一般情况下 `while` 循环格式:
```swift > while `condition` {
while `condition` { > `statements`
`statements` > }
}
```
下面的例子来玩一个叫做_蛇和梯子Snakes and Ladders_的小游戏也叫做_滑道和梯子Chutes and Ladders_ 下面的例子来玩一个叫做_蛇和梯子Snakes and Ladders_的小游戏也叫做_滑道和梯子Chutes and Ladders_
@ -250,11 +240,9 @@ println("Game over!")
下面是一般情况下 `do-while`循环的格式: 下面是一般情况下 `do-while`循环的格式:
```swift > do {
do { > `statements`
`statements` > } while `condition`
} while `condition`
```
还是蛇和梯子的游戏,使用`do-while`循环来替代`while`循环。`finalSquare``board``square``diceRoll`的值初始化同`while`循环一样: 还是蛇和梯子的游戏,使用`do-while`循环来替代`while`循环。`finalSquare``board``square``diceRoll`的值初始化同`while`循环一样:
@ -359,17 +347,15 @@ if temperatureInFahrenheit <= 32 {
`switch`语句最简单的形式就是把某个值与一个或若干个相同类型的值作比较: `switch`语句最简单的形式就是把某个值与一个或若干个相同类型的值作比较:
```swift > switch `some value to consider` {
switch `some value to consider` { > case `value 1`:
case `value 1`: > `respond to value 1`
`respond to value 1` > case `value 2`,
case `value 2`, > `value 3`:
`value 3`: > `respond to value 2 or 3`
`respond to value 2 or 3` > default:
default: > `otherwise, do something else`
`otherwise, do something else` > }
}
```
`switch`语句都由*多个 case* 构成。为了匹配某些更特定的值Swift 提供了几种更复杂的匹配模式,这些模式将在本节的稍后部分提到。 `switch`语句都由*多个 case* 构成。为了匹配某些更特定的值Swift 提供了几种更复杂的匹配模式,这些模式将在本节的稍后部分提到。
@ -402,8 +388,7 @@ default:
与 C 语言和 Objective-C 中的`switch`语句不同,在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止`switch`语句,而不会继续执行下一个 case 分支。这也就是说,不需要在 case 分支中显式地使用`break`语句。这使得`switch`语句更安全、更易用,也避免了因忘记写`break`语句而产生的错误。 与 C 语言和 Objective-C 中的`switch`语句不同,在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止`switch`语句,而不会继续执行下一个 case 分支。这也就是说,不需要在 case 分支中显式地使用`break`语句。这使得`switch`语句更安全、更易用,也避免了因忘记写`break`语句而产生的错误。
> 注意: > 注意:
>
你依然可以在 case 分支中的代码执行完毕前跳出,详情请参考[Switch 语句中的 break](#break_in_a_switch_statement)。 你依然可以在 case 分支中的代码执行完毕前跳出,详情请参考[Switch 语句中的 break](#break_in_a_switch_statement)。
每一个 case 分支都*必须*包含至少一条语句。像下面这样书写代码是无效的,因为第一个 case 分支是空的: 每一个 case 分支都*必须*包含至少一条语句。像下面这样书写代码是无效的,因为第一个 case 分支是空的:
@ -424,15 +409,13 @@ default:
一个 case 也可以包含多个模式,用逗号把它们分开(如果太长了也可以分行写): 一个 case 也可以包含多个模式,用逗号把它们分开(如果太长了也可以分行写):
```swift > switch `some value to consider` {
switch `some value to consider` { > case `value 1`,
case `value 1`, > `value 2`:
`value 2`: > `statements`
`statements` > }
}
```
> 注意: > 注意:
如果想要贯穿至特定的 case 分支中,请使用`fallthrough`语句,详情请参考[贯穿Fallthrough](#fallthrough)。 如果想要贯穿至特定的 case 分支中,请使用`fallthrough`语句,详情请参考[贯穿Fallthrough](#fallthrough)。
<a name="range_matching"></a> <a name="range_matching"></a>
@ -560,10 +543,10 @@ case let (x, y):
控制转移语句改变你代码的执行顺序通过它你可以实现代码的跳转。Swift有四种控制转移语句。 控制转移语句改变你代码的执行顺序通过它你可以实现代码的跳转。Swift有四种控制转移语句。
- continue - continue
- break - break
- fallthrough - fallthrough
- return - return
我们将会在下面讨论`continue`、`break`和`fallthrough`语句。`return`语句将会在[函数](../chapter2/06_Functions.html)章节讨论。 我们将会在下面讨论`continue`、`break`和`fallthrough`语句。`return`语句将会在[函数](../chapter2/06_Functions.html)章节讨论。
@ -572,8 +555,7 @@ case let (x, y):
`continue`语句告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。就好像在说“本次循环迭代我已经执行完了”,但是并不会离开整个循环体。 `continue`语句告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。就好像在说“本次循环迭代我已经执行完了”,但是并不会离开整个循环体。
>注意: >注意:
>
在一个for条件递增`for-condition-increment`)循环体中,在调用`continue`语句后,迭代增量仍然会被计算求值。循环体继续像往常一样工作,仅仅只是循环体中的执行代码会被跳过。 在一个for条件递增`for-condition-increment`)循环体中,在调用`continue`语句后,迭代增量仍然会被计算求值。循环体继续像往常一样工作,仅仅只是循环体中的执行代码会被跳过。
下面的例子把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句: 下面的例子把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句:
@ -612,8 +594,7 @@ println(puzzleOutput)
这种特性可以被用来匹配或者忽略一个或多个分支。因为 Swift 的`switch`需要包含所有的分支而且不允许有为空的分支,有时为了使你的意图更明显,需要特意匹配或者忽略某个分支。那么当你想忽略某个分支时,可以在该分支内写上`break`语句。当那个分支被匹配到时,分支内的`break`语句立即结束`switch`代码块。 这种特性可以被用来匹配或者忽略一个或多个分支。因为 Swift 的`switch`需要包含所有的分支而且不允许有为空的分支,有时为了使你的意图更明显,需要特意匹配或者忽略某个分支。那么当你想忽略某个分支时,可以在该分支内写上`break`语句。当那个分支被匹配到时,分支内的`break`语句立即结束`switch`代码块。
>注意: >注意:
>
当一个`switch`分支仅仅包含注释时,会被报编译时错误。注释不是代码语句而且也不能让`switch`分支达到被忽略的效果。你总是可以使用`break`来忽略某个分支。 当一个`switch`分支仅仅包含注释时,会被报编译时错误。注释不是代码语句而且也不能让`switch`分支达到被忽略的效果。你总是可以使用`break`来忽略某个分支。
下面的例子通过`switch`来判断一个`Character`值是否代表下面四种语言之一。为了简洁,多个值被包含在了同一个分支情况中。 下面的例子通过`switch`来判断一个`Character`值是否代表下面四种语言之一。为了简洁,多个值被包含在了同一个分支情况中。
@ -674,8 +655,7 @@ println(description)
当`switch`代码块执行完后,使用`println`函数打印该数字的描述。在这个例子中,数字`5`被准确的识别为了一个质数。 当`switch`代码块执行完后,使用`println`函数打印该数字的描述。在这个例子中,数字`5`被准确的识别为了一个质数。
>注意: >注意:
>
`fallthrough`关键字不会检查它下一个将会落入执行的 case 中的匹配条件。`fallthrough`简单地使代码执行继续连接到下一个 case 中的执行代码,这和 C 语言标准中的`switch`语句特性是一样的。 `fallthrough`关键字不会检查它下一个将会落入执行的 case 中的匹配条件。`fallthrough`简单地使代码执行继续连接到下一个 case 中的执行代码,这和 C 语言标准中的`switch`语句特性是一样的。
<a name="labeled_statements"></a> <a name="labeled_statements"></a>
@ -687,11 +667,9 @@ println(description)
产生一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,并且该标签后面还需带着一个冒号。下面是一个`while`循环体的语法,同样的规则适用于所有的循环体和`switch`代码块。 产生一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,并且该标签后面还需带着一个冒号。下面是一个`while`循环体的语法,同样的规则适用于所有的循环体和`switch`代码块。
``` > `label name`: while `condition` {
`label name`: while `condition` { > `statements`
`statements` > }
}
```
下面的例子是在一个带有标签的`while`循环体中调用`break`和`continue`语句该循环体是前面章节中_蛇和梯子_的改编版本。这次游戏增加了一条额外的规则 下面的例子是在一个带有标签的`while`循环体中调用`break`和`continue`语句该循环体是前面章节中_蛇和梯子_的改编版本。这次游戏增加了一条额外的规则
@ -740,12 +718,9 @@ println("Game over!")
每次循环迭代开始时掷骰子。与之前玩家掷完骰子就立即移动不同,这里使用了`switch`来考虑每次移动可能产生的结果,从而决定玩家本次是否能够移动。 每次循环迭代开始时掷骰子。与之前玩家掷完骰子就立即移动不同,这里使用了`switch`来考虑每次移动可能产生的结果,从而决定玩家本次是否能够移动。
- 如果骰子数刚好使玩家移动到最终的方格里,游戏结束。`break gameLoop`语句跳转控制去执行`while`循环体后的第一行代码,游戏结束。 - 如果骰子数刚好使玩家移动到最终的方格里,游戏结束。`break gameLoop`语句跳转控制去执行`while`循环体后的第一行代码,游戏结束。
- 如果骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子。`continue gameLoop`语句结束本次`while`循环的迭代,开始下一次循环迭代。 - 如果骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子。`continue gameLoop`语句结束本次`while`循环的迭代,开始下一次循环迭代。
- 在剩余的所有情况中,骰子数产生的都是合法的移动。玩家向前移动骰子数个方格,然后游戏逻辑再处理玩家当前是否处于蛇头或者梯子的底部。本次循环迭代结束,控制跳转到`while`循环体的条件判断语句处,再决定是否能够继续执行下次循环迭代。 - 在剩余的所有情况中,骰子数产生的都是合法的移动。玩家向前移动骰子数个方格,然后游戏逻辑再处理玩家当前是否处于蛇头或者梯子的底部。本次循环迭代结束,控制跳转到`while`循环体的条件判断语句处,再决定是否能够继续执行下次循环迭代。
>注意: >注意:
>
如果上述的`break`语句没有使用`gameLoop`标签,那么它将会中断`switch`代码块而不是`while`循环体。使用`gameLoop`标签清晰的表明了`break`想要中断的是哪个代码块。 如果上述的`break`语句没有使用`gameLoop`标签,那么它将会中断`switch`代码块而不是`while`循环体。使用`gameLoop`标签清晰的表明了`break`想要中断的是哪个代码块。
同时请注意,当调用`continue gameLoop`去跳转到下一次循环迭代时,这里使用`gameLoop`标签并不是严格必须的。因为在这个游戏中,只有一个循环体,所以`continue`语句会影响到哪个循环体是没有歧义的。然而,`continue`语句使用`gameLoop`标签也是没有危害的。这样做符合标签的使用规则,同时参照旁边的`break gameLoop`能够使游戏的逻辑更加清晰和易于理解 同时请注意,当调用`continue gameLoop`去跳转到下一次循环迭代时,这里使用`gameLoop`标签并不是严格必须的。因为在这个游戏中,只有一个循环体,所以`continue`语句会影响到哪个循环体是没有歧义的。然而,`continue`语句使用`gameLoop`标签也是没有危害的。这样做符合标签的使用规则,同时参照旁边的`break gameLoop`能够使游戏的逻辑更加清晰和易于理解

View File

@ -1,23 +1,23 @@
> 翻译honghaoz > 翻译honghaoz
> 校对LunaticM
> 校对LunaticM
# 函数Functions # 函数Functions
----------------- -----------------
本页包含内容: 本页包含内容:
- [函数定义与调用Defining and Calling Functions](#Defining_and_Calling_Functions) - [函数定义与调用Defining and Calling Functions](#Defining_and_Calling_Functions)
- [函数参数与返回值Function Parameters and Return Values](#Function_Parameters_and_Return_Values) - [函数参数与返回值Function Parameters and Return Values](#Function_Parameters_and_Return_Values)
- [函数参数名称Function Parameter Names](#Function_Parameter_Names) - [函数参数名称Function Parameter Names](#Function_Parameter_Names)
- [函数类型Function Types](#Function_Types) - [函数类型Function Types](#Function_Types)
- [函数嵌套Nested Functions](#Nested_Functions) - [函数嵌套Nested Functions](#Nested_Functions)
函数是用来完成特定任务的独立的代码块。你给一个函数起一个合适的名字,用来标示函数做什么,并且当函数需要执行的时候,这个名字会被“调用”。 函数是用来完成特定任务的独立的代码块。你给一个函数起一个合适的名字,用来标示函数做什么,并且当函数需要执行的时候,这个名字会被“调用”。
Swift 统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以即当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值可以被修改。 Swift 统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以即当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值可以被修改。
在 Swift 中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。 在 Swift 中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。
<a name="Defining_and_Calling_Functions"></a> <a name="Defining_and_Calling_Functions"></a>
## 函数的定义与调用Defining and Calling Functions ## 函数的定义与调用Defining and Calling Functions
@ -79,6 +79,7 @@ func halfOpenRangeLength(start: Int, end: Int) -> Int {
println(halfOpenRangeLength(1, 10)) println(halfOpenRangeLength(1, 10))
// prints "9 // prints "9
``` ```
### 无参函数Functions Without Parameters ### 无参函数Functions Without Parameters
函数可以没有参数。下面这个函数就是一个无参函数,当被调用时,它返回固定的 `String` 消息: 函数可以没有参数。下面这个函数就是一个无参函数,当被调用时,它返回固定的 `String` 消息:
@ -107,9 +108,8 @@ sayGoodbye("Dave")
因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。 因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。
> 注意: > 注意:
> > 严格上来说,虽然没有返回值被定义,`sayGoodbye` 函数依然返回了值。没有定义返回类型的函数会返回特殊的值,叫 `Void`。它其实是一个空的元组tuple没有任何元素可以写成`()`。
> 严格上来说,虽然没有返回值被定义,`sayGoodbye` 函数依然返回了值。没有定义返回类型的函数会返回特殊的值,叫 `Void`。它其实是一个空的元组tuple没有任何元素可以写成`()`。
被调用时,一个函数的返回值可以被忽略: 被调用时,一个函数的返回值可以被忽略:
@ -130,9 +130,8 @@ printWithoutCounting("hello, world")
第一个函数 `printAndCount`,输出一个字符串并返回 `Int` 类型的字符数。第二个函数 `printWithoutCounting`调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,消息依然会由第一个函数输出,但是返回值不会被用到。 第一个函数 `printAndCount`,输出一个字符串并返回 `Int` 类型的字符数。第二个函数 `printWithoutCounting`调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,消息依然会由第一个函数输出,但是返回值不会被用到。
> 注意: > 注意:
> > 返回值可以被忽略但定义了有返回值的函数必须返回一个值如果在函数定义底部没有返回任何值这叫导致编译错误compile-time error
> 返回值可以被忽略但定义了有返回值的函数必须返回一个值如果在函数定义底部没有返回任何值这叫导致编译错误compile-time error
### 多重返回值函数Functions with Multiple Return Values ### 多重返回值函数Functions with Multiple Return Values
@ -160,11 +159,14 @@ func count(string: String) -> (vowels: Int, consonants: Int, others: Int) {
你可以用 `count` 函数来处理任何一个字符串,返回的值将是一个包含三个 `Int` 型值的元组tuple 你可以用 `count` 函数来处理任何一个字符串,返回的值将是一个包含三个 `Int` 型值的元组tuple
let total = count("some arbitrary string!") ```swift
println("\(total.vowels) vowels and \(total.consonants) consonants") let total = count("some arbitrary string!")
// prints "6 vowels and 13 consonants println("\(total.vowels) vowels and \(total.consonants) consonants")
// prints "6 vowels and 13 consonants
```
需要注意的是,元组的成员不需要在函数中返回时命名,因为它们的名字已经在函数返回类型有有了定义。 需要注意的是,元组的成员不需要在函数中返回时命名,因为它们的名字已经在函数返回类型有有了定义。
<a name="Function_Parameter_Names"></a> <a name="Function_Parameter_Names"></a>
## 函数参数名称Function Parameter Names ## 函数参数名称Function Parameter Names
@ -192,9 +194,8 @@ func someFunction(externalParameterName localParameterName: Int) {
} }
``` ```
> 注意: > 注意:
> > 如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。
> 如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。
以下是个例子,这个函数使用一个`结合者joiner`把两个字符串联在一起: 以下是个例子,这个函数使用一个`结合者joiner`把两个字符串联在一起:
@ -230,9 +231,8 @@ join(string: "hello", toString: "world", withJoiner: ", ")
使用外部参数名让第二个版本的 `join` 函数的调用更为有表现力,更为通顺,同时还保持了函数体是可读的和有明确意图的。 使用外部参数名让第二个版本的 `join` 函数的调用更为有表现力,更为通顺,同时还保持了函数体是可读的和有明确意图的。
> 注意: > 注意:
> > 当其他人在第一次读你的代码,函数参数的意图显得不明显时,考虑使用外部参数名。如果函数参数名的意图是很明显的,那就不需要定义外部参数名了。
> 当其他人在第一次读你的代码,函数参数的意图显得不明显时,考虑使用外部参数名。如果函数参数名的意图是很明显的,那就不需要定义外部参数名了。
### 简写外部参数名Shorthand External Parameter Names ### 简写外部参数名Shorthand External Parameter Names
@ -262,9 +262,8 @@ let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
你可以在函数体中为每个参数定义`默认值`。当默认值被定义后,调用这个函数时可以略去这个参数。 你可以在函数体中为每个参数定义`默认值`。当默认值被定义后,调用这个函数时可以略去这个参数。
> 注意: > 注意:
> > 将带有默认值的参数放在函数参数表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。
> 将带有默认值的参数放在函数参数表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。
以下是另一个版本的`join`函数,其中`joiner`有了默认参数值: 以下是另一个版本的`join`函数,其中`joiner`有了默认参数值:
@ -287,6 +286,7 @@ join(string: "hello", toString: "world", withJoiner: "-")
join(string: "hello", toString:"world") join(string: "hello", toString:"world")
// returns "hello world" // returns "hello world"
``` ```
### 默认值参数的外部参数名External Names for Parameters with Default Values ### 默认值参数的外部参数名External Names for Parameters with Default Values
在大多数情况下,给带默认值的参数起一个外部参数名是很有用的。这样可以保证当函数被调用且带默认值的参数被提供值时,实参的意图是明显的。 在大多数情况下,给带默认值的参数起一个外部参数名是很有用的。这样可以保证当函数被调用且带默认值的参数被提供值时,实参的意图是明显的。
@ -308,9 +308,8 @@ join("hello", "world", joiner: "-")
// returns "hello-world" // returns "hello-world"
``` ```
> 注意: > 注意:
> > 你可以使用`下划线_`作为默认值参数的外部参数名,这样可以在调用时不用提供外部参数名。但是给带默认值的参数命名总是更加合适的。
> 你可以使用`下划线_`作为默认值参数的外部参数名,这样可以在调用时不用提供外部参数名。但是给带默认值的参数命名总是更加合适的。
### 可变参数Variadic Parameters ### 可变参数Variadic Parameters
@ -324,7 +323,7 @@ join("hello", "world", joiner: "-")
func arithmeticMean(numbers: Double...) -> Double { func arithmeticMean(numbers: Double...) -> Double {
var total: Double = 0 var total: Double = 0
for number in numbers { for number in numbers {
total += number total += number
} }
return total / Double(numbers.count) return total / Double(numbers.count)
} }
@ -334,9 +333,8 @@ arithmeticMean(3, 8, 19)
// returns 10.0, which is the arithmetic mean of these three numbers // returns 10.0, which is the arithmetic mean of these three numbers
``` ```
> 注意: > 注意:
> > 一个函数至多能有一个可变参数,而且它必须是参数表中最后的一个。这样做是为了避免函数调用时出现歧义。
> 一个函数至多能有一个可变参数,而且它必须是参数表中最后的一个。这样做是为了避免函数调用时出现歧义。
如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后。 如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后。
@ -368,9 +366,8 @@ let paddedString = alignRight(originalString, 10, "-")
该函数首先计算出多少个字符需要被添加到 `string` 的左边,以右对齐到总的字符串中。这个值存在局部常量 `amountToPad` 中。这个函数然后将 `amountToPad` 多的填充pad字符填充到 `string` 左边,并返回结果。它使用了 `string` 这个变量参数来进行所有字符串操作。 该函数首先计算出多少个字符需要被添加到 `string` 的左边,以右对齐到总的字符串中。这个值存在局部常量 `amountToPad` 中。这个函数然后将 `amountToPad` 多的填充pad字符填充到 `string` 左边,并返回结果。它使用了 `string` 这个变量参数来进行所有字符串操作。
> 注意: > 注意:
> > 对变量参数所进行的修改在函数调用结束后便消失了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中。
> 对变量参数所进行的修改在函数调用结束后便消失了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中。
### 输入输出参数In-Out Parameters ### 输入输出参数In-Out Parameters
@ -380,9 +377,8 @@ let paddedString = alignRight(originalString, 10, "-")
你只能传入一个变量作为输入输出参数。你不能传入常量或者字面量literal value因为这些量是不能被修改的。当传入的参数作为输入输出参数时需要在参数前加`&`符,表示这个值可以被函数修改。 你只能传入一个变量作为输入输出参数。你不能传入常量或者字面量literal value因为这些量是不能被修改的。当传入的参数作为输入输出参数时需要在参数前加`&`符,表示这个值可以被函数修改。
> 注意: > 注意:
> > 输入输出参数不能有默认值,而且可变参数不能用 `inout` 标记。如果你用 `inout` 标记一个参数,这个参数不能被 `var` 或者 `let` 标记。
> 输入输出参数不能有默认值,而且可变参数不能用 `inout` 标记。如果你用 `inout` 标记一个参数,这个参数不能被 `var` 或者 `let` 标记。
下面是例子,`swapTwoInts` 函数,有两个分别叫做 `a``b` 的输出输出参数: 下面是例子,`swapTwoInts` 函数,有两个分别叫做 `a``b` 的输出输出参数:
@ -408,9 +404,8 @@ println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
从上面这个例子中,我们可以看到 `someInt``anotherInt` 的原始值在 `swapTwoInts` 函数中被修改,尽管它们的定义在函数体外。 从上面这个例子中,我们可以看到 `someInt``anotherInt` 的原始值在 `swapTwoInts` 函数中被修改,尽管它们的定义在函数体外。
> 注意: > 注意:
> > 输出输出参数和返回值是不一样的。上面的 `swapTwoInts` 函数并没有定义任何返回值,但仍然修改了 `someInt` 和 `anotherInt` 的值。输入输出参数是函数对函数体外产生影响的另一种方式。
> 输出输出参数和返回值是不一样的。上面的 `swapTwoInts` 函数并没有定义任何返回值,但仍然修改了 `someInt` 和 `anotherInt` 的值。输入输出参数是函数对函数体外产生影响的另一种方式。
<a name="Function_Types"></a> <a name="Function_Types"></a>
## 函数类型Function Types ## 函数类型Function Types
@ -477,6 +472,7 @@ println("Result: \(mathFunction(2, 3))")
let anotherMathFunction = addTwoInts let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -> Int // anotherMathFunction is inferred to be of type (Int, Int) -> Int
``` ```
### 函数类型作为参数类型Function Types as Parameter Types ### 函数类型作为参数类型Function Types as Parameter Types
你可以用`(Int, Int) -> Int`这样的函数类型作为另一个函数的参数类型。这样你可以将函数的一部分实现交由给函数的调用者。 你可以用`(Int, Int) -> Int`这样的函数类型作为另一个函数的参数类型。这样你可以将函数的一部分实现交由给函数的调用者。
@ -574,4 +570,4 @@ println("zero!")
// -2... // -2...
// -1... // -1...
// zero! // zero!
``` ```

View File

@ -1,16 +1,15 @@
> 翻译wh1100717 > 翻译wh1100717
> 校对lyuka
> 校对lyuka
# 闭包Closures # 闭包Closures
----------------- -----------------
本页包含内容: 本页包含内容:
- [闭包表达式Closure Expressions](#closure_expressions) - [闭包表达式Closure Expressions](#closure_expressions)
- [尾随闭包Trailing Closures](#trailing_closures) - [尾随闭包Trailing Closures](#trailing_closures)
- [值捕获Capturing Values](#capturing_values) - [值捕获Capturing Values](#capturing_values)
- [闭包是引用类型Closures Are Reference Types](#closures_are_reference_types) - [闭包是引用类型Closures Are Reference Types](#closures_are_reference_types)
闭包是自包含的函数代码块,可以在代码中被传递和使用。 闭包是自包含的函数代码块,可以在代码中被传递和使用。
Swift 中的闭包与 C 和 Objective-C 中的代码块blocks以及其他一些编程语言中的 lambdas 函数比较相似。 Swift 中的闭包与 C 和 Objective-C 中的代码块blocks以及其他一些编程语言中的 lambdas 函数比较相似。
@ -18,22 +17,21 @@ Swift 中的闭包与 C 和 Objective-C 中的代码块blocks以及其他
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。
这就是所谓的闭合并包裹着这些常量和变量俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。 这就是所谓的闭合并包裹着这些常量和变量俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。
> 注意: > 注意:
> > 如果您不熟悉捕获capturing这个概念也不用担心您可以在 [值捕获](#capturing_values) 章节对其进行详细了解。
> 如果您不熟悉捕获capturing这个概念也不用担心您可以在 [值捕获](#capturing_values) 章节对其进行详细了解。
在[函数](../chapter2/06_Functions.html) 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一: 在[函数](../chapter2/06_Functions.html) 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:
* 全局函数是一个有名字但不会捕获任何值的闭包 * 全局函数是一个有名字但不会捕获任何值的闭包
* 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包 * 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包
* 闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的匿名闭包 * 闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的匿名闭包
Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下: Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下:
* 利用上下文推断参数和返回值类型 * 利用上下文推断参数和返回值类型
* 隐式返回单表达式闭包,即单表达式闭包可以省略`return`关键字 * 隐式返回单表达式闭包,即单表达式闭包可以省略`return`关键字
* 参数名称缩写 * 参数名称缩写
* 尾随Trailing闭包语法 * 尾随Trailing闭包语法
<a name="closure_expressions"></a> <a name="closure_expressions"></a>
## 闭包表达式Closure Expressions ## 闭包表达式Closure Expressions
@ -54,20 +52,20 @@ Swift 标准库提供了`sort`函数,会根据您提供的基于输出类型
下面的闭包表达式示例使用`sort`函数对一个`String`类型的数组进行字母逆序排序,以下是初始数组值: 下面的闭包表达式示例使用`sort`函数对一个`String`类型的数组进行字母逆序排序,以下是初始数组值:
``` ```swift
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
``` ```
`sort`函数需要传入两个参数: `sort`函数需要传入两个参数:
* 已知类型的数组 * 已知类型的数组
* 闭包函数,该闭包函数需要传入与数组类型相同的两个值,并返回一个布尔类型值来告诉`sort`函数当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回`true`,反之返回`false` * 闭包函数,该闭包函数需要传入与数组类型相同的两个值,并返回一个布尔类型值来告诉`sort`函数当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回`true`,反之返回`false`
该例子对一个`String`类型的数组进行排序,因此排序闭包函数类型需为`(String, String) -> Bool` 该例子对一个`String`类型的数组进行排序,因此排序闭包函数类型需为`(String, String) -> Bool`
提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为`sort`函数的第二个参数传入: 提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为`sort`函数的第二个参数传入:
``` ```swift
func backwards(s1: String, s2: String) -> Bool { func backwards(s1: String, s2: String) -> Bool {
return s1 > s2 return s1 > s2
} }
@ -88,7 +86,7 @@ var reversed = sort(names, backwards)
闭包表达式语法有如下一般形式: 闭包表达式语法有如下一般形式:
``` ```swift
{ (parameters) -> returnType in { (parameters) -> returnType in
statements statements
} }
@ -100,10 +98,10 @@ var reversed = sort(names, backwards)
下面的例子展示了之前`backwards`函数对应的闭包表达式版本的代码: 下面的例子展示了之前`backwards`函数对应的闭包表达式版本的代码:
``` ```swift
reversed = sort(names, { (s1: String, s2: String) -> Bool in reversed = sort(names, { (s1: String, s2: String) -> Bool in
return s1 > s2 return s1 > s2
}) })
``` ```
需要注意的是内联闭包参数和返回值类型声明与`backwards`函数类型声明相同。 需要注意的是内联闭包参数和返回值类型声明与`backwards`函数类型声明相同。
@ -115,7 +113,7 @@ reversed = sort(names, { (s1: String, s2: String) -> Bool in
因为这个闭包的函数体部分如此短以至于可以将其改写成一行代码: 因为这个闭包的函数体部分如此短以至于可以将其改写成一行代码:
``` ```swift
reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } ) reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )
``` ```
@ -128,7 +126,7 @@ reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )
`sort`期望第二个参数是类型为`(String, String) -> Bool`的函数,因此实际上`String`,`String``Bool`类型并不需要作为闭包表达式定义中的一部分。 `sort`期望第二个参数是类型为`(String, String) -> Bool`的函数,因此实际上`String`,`String``Bool`类型并不需要作为闭包表达式定义中的一部分。
因为所有的类型都可以被正确推断,返回箭头 (`->`) 和围绕在参数周围的括号也可以被省略: 因为所有的类型都可以被正确推断,返回箭头 (`->`) 和围绕在参数周围的括号也可以被省略:
``` ```swift
reversed = sort(names, { s1, s2 in return s1 > s2 } ) reversed = sort(names, { s1, s2 in return s1 > s2 } )
``` ```
@ -139,7 +137,7 @@ reversed = sort(names, { s1, s2 in return s1 > s2 } )
单行表达式闭包可以通过隐藏`return`关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为: 单行表达式闭包可以通过隐藏`return`关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为:
``` ```swift
reversed = sort(names, { s1, s2 in s1 > s2 } ) reversed = sort(names, { s1, s2 in s1 > s2 } )
``` ```
@ -154,7 +152,7 @@ Swift 自动为内联函数提供了参数名称缩写功能,您可以直接
如果您在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。 如果您在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。
`in`关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成: `in`关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
``` ```swift
reversed = sort(names, { $0 > $1 } ) reversed = sort(names, { $0 > $1 } )
``` ```
@ -168,7 +166,7 @@ Swift 的`String`类型定义了关于大于号 (`>`) 的字符串实现,其
而这正好与`sort`函数的第二个参数需要的函数类型相符合。 而这正好与`sort`函数的第二个参数需要的函数类型相符合。
因此您可以简单地传递一个大于号Swift可以自动推断出您想使用大于号的字符串函数实现 因此您可以简单地传递一个大于号Swift可以自动推断出您想使用大于号的字符串函数实现
``` ```swift
reversed = sort(names, >) reversed = sort(names, >)
``` ```
@ -181,32 +179,28 @@ reversed = sort(names, >)
如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。 如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。
尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。 尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。
``` ```swift
func someFunctionThatTakesAClosure(closure: () -> ()) { func someFunctionThatTakesAClosure(closure: () -> ()) {
// 函数体部分 // 函数体部分
} }
// 以下是不使用尾随闭包进行函数调用 // 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({ someFunctionThatTakesAClosure({
// 闭包主体部分 // 闭包主体部分
}) })
// 以下是使用尾随闭包进行函数调用 // 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() { someFunctionThatTakesAClosure() {
// 闭包主体部分 // 闭包主体部分
} }
``` ```
> 注意: > 注意:
> > 如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把`()`省略掉。
> 如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把`()`省略掉。
在上例中作为`sort`函数参数的字符串排序闭包可以改写为: 在上例中作为`sort`函数参数的字符串排序闭包可以改写为:
``` ```swift
reversed = sort(names) { $0 > $1 } reversed = sort(names) { $0 > $1 }
``` ```
@ -219,7 +213,7 @@ reversed = sort(names) { $0 > $1 }
下例介绍了如何在`map`方法中使用尾随闭包将`Int`类型数组`[16,58,510]`转换为包含对应`String`类型的数组`["OneSix", "FiveEight", "FiveOneZero"]`: 下例介绍了如何在`map`方法中使用尾随闭包将`Int`类型数组`[16,58,510]`转换为包含对应`String`类型的数组`["OneSix", "FiveEight", "FiveOneZero"]`:
``` ```swift
let digitNames = [ let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four", 0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine" 5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
@ -233,7 +227,7 @@ let numbers = [16, 58, 510]
您现在可以通过传递一个尾随闭包给`numbers``map`方法来创建对应的字符串版本数组。 您现在可以通过传递一个尾随闭包给`numbers``map`方法来创建对应的字符串版本数组。
需要注意的时调用`numbers.map`不需要在`map`后面包含任何括号,因为其只需要传递闭包表达式这一个参数,并且该闭包表达式参数通过尾随方式进行撰写: 需要注意的时调用`numbers.map`不需要在`map`后面包含任何括号,因为其只需要传递闭包表达式这一个参数,并且该闭包表达式参数通过尾随方式进行撰写:
``` ```swift
let strings = numbers.map { let strings = numbers.map {
(var number) -> String in (var number) -> String in
var output = "" var output = ""
@ -255,11 +249,10 @@ let strings = numbers.map {
闭包表达式在每次被调用的时候创建了一个字符串并返回。 闭包表达式在每次被调用的时候创建了一个字符串并返回。
其使用求余运算符 (number % 10) 计算最后一位数字并利用`digitNames`字典获取所映射的字符串。 其使用求余运算符 (number % 10) 计算最后一位数字并利用`digitNames`字典获取所映射的字符串。
> 注意: > 注意:
> > 字典`digitNames`下标后跟着一个叹号 (!),因为字典下标返回一个可选值 (optional value),表明即使该 key 不存在也不会查找失败。
> 字典`digitNames`下标后跟着一个叹号 (!),因为字典下标返回一个可选值 (optional value),表明即使该 key 不存在也不会查找失败。 > 在上例中,它保证了`number % 10`可以总是作为一个`digitNames`字典的有效下标 key。
> 在上例中,它保证了`number % 10`可以总是作为一个`digitNames`字典的有效下标 key。 > 因此叹号可以用于强制解析 (force-unwrap) 存储在可选下标项中的`String`类型值。
> 因此叹号可以用于强制解析 (force-unwrap) 存储在可选下标项中的`String`类型值。
`digitNames`字典中获取的字符串被添加到输出的前部,逆序建立了一个字符串版本的数字。 `digitNames`字典中获取的字符串被添加到输出的前部,逆序建立了一个字符串版本的数字。
(在表达式`number % 10`如果number为16则返回658返回8510返回0 (在表达式`number % 10`如果number为16则返回658返回8510返回0
@ -287,7 +280,7 @@ Swift最简单的闭包形式是嵌套函数也就是定义在其他函数的
之后`makeIncrementor``incrementor`作为闭包返回。 之后`makeIncrementor``incrementor`作为闭包返回。
每次调用`incrementor`时,其会以`amount`作为增量增加`runningTotal`的值。 每次调用`incrementor`时,其会以`amount`作为增量增加`runningTotal`的值。
``` ```swift
func makeIncrementor(forIncrement amount: Int) -> () -> Int { func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0 var runningTotal = 0
func incrementor() -> Int { func incrementor() -> Int {
@ -313,7 +306,7 @@ func makeIncrementor(forIncrement amount: Int) -> () -> Int {
如果我们单独看这个函数,会发现看上去不同寻常: 如果我们单独看这个函数,会发现看上去不同寻常:
``` ```swift
func incrementor() -> Int { func incrementor() -> Int {
runningTotal += amount runningTotal += amount
return runningTotal return runningTotal
@ -326,22 +319,21 @@ func incrementor() -> Int {
然而,因为每次调用该函数的时候都会修改`runningTotal`的值,`incrementor`捕获了当前`runningTotal`变量的引用,而不是仅仅复制该变量的初始值。捕获一个引用保证了当`makeIncrementor`结束时候并不会消失,也保证了当下一次执行`incrementor`函数时,`runningTotal`可以继续增加。 然而,因为每次调用该函数的时候都会修改`runningTotal`的值,`incrementor`捕获了当前`runningTotal`变量的引用,而不是仅仅复制该变量的初始值。捕获一个引用保证了当`makeIncrementor`结束时候并不会消失,也保证了当下一次执行`incrementor`函数时,`runningTotal`可以继续增加。
> 注意: > 注意:
> > Swift 会决定捕获引用还是拷贝值。
> Swift 会决定捕获引用还是拷贝值。 > 您不需要标注`amount`或者`runningTotal`来声明在嵌入的`incrementor`函数中的使用方式。
> 您不需要标注`amount`或者`runningTotal`来声明在嵌入的`incrementor`函数中的使用方式。 > Swift 同时也处理`runingTotal`变量的内存管理操作,如果不再被`incrementor`函数使用,则会被清除。
> Swift 同时也处理`runingTotal`变量的内存管理操作,如果不再被`incrementor`函数使用,则会被清除。
下面代码为一个使用`makeIncrementor`的例子: 下面代码为一个使用`makeIncrementor`的例子:
``` ```swift
let incrementByTen = makeIncrementor(forIncrement: 10) let incrementByTen = makeIncrementor(forIncrement: 10)
``` ```
该例子定义了一个叫做`incrementByTen`的常量该常量指向一个每次调用会加10的`incrementor`函数。 该例子定义了一个叫做`incrementByTen`的常量该常量指向一个每次调用会加10的`incrementor`函数。
调用这个函数多次可以得到以下结果: 调用这个函数多次可以得到以下结果:
``` ```swift
incrementByTen() incrementByTen()
// 返回的值为10 // 返回的值为10
incrementByTen() incrementByTen()
@ -353,7 +345,7 @@ incrementByTen()
如果您创建了另一个`incrementor`,其会有一个属于自己的独立的`runningTotal`变量的引用。 如果您创建了另一个`incrementor`,其会有一个属于自己的独立的`runningTotal`变量的引用。
下面的例子中,`incrementBySevne`捕获了一个新的`runningTotal`变量,该变量和`incrementByTen`中捕获的变量没有任何联系: 下面的例子中,`incrementBySevne`捕获了一个新的`runningTotal`变量,该变量和`incrementByTen`中捕获的变量没有任何联系:
``` ```swift
let incrementBySeven = makeIncrementor(forIncrement: 7) let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven() incrementBySeven()
// 返回的值为7 // 返回的值为7
@ -361,15 +353,13 @@ incrementByTen()
// 返回的值为40 // 返回的值为40
``` ```
> 注意: > 注意:
> > 如果您将闭包赋值给一个类实例的属性,并且该闭包通过指向该实例或其成员来捕获了该实例,您将创建一个在闭包和实例间的强引用环。
> 如果您闭包分配给一个类实例的属性,并且该闭包通过指向该实例或其成员来捕获了该实例,您将创建一个在闭包和实例间的强引用环。 > Swift 使用捕获列表来打破这种强引用环。更多信息,请参考 [闭包引起的循环强引用](../chapter2/16_Automatic_Reference_Counting.html#strong_reference_cycles_for_closures)。
> Swift 使用捕获列表来打破这种强引用环。更多信息,请参考 [闭包引起的循环强引用](../chapter2/16_Automatic_Reference_Counting.html#strong_reference_cycles_for_closures)。
<a name="closures_are_reference_types"></a> <a name="closures_are_reference_types"></a>
## 闭包是引用类型Closures Are Reference Types ## 闭包是引用类型Closures Are Reference Types
上面的例子中,`incrementBySeven``incrementByTen`是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量值。 上面的例子中,`incrementBySeven``incrementByTen`是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量值。
这是因为函数和闭包都是引用类型。 这是因为函数和闭包都是引用类型。
@ -378,12 +368,8 @@ incrementByTen()
这也意味着如果您将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包: 这也意味着如果您将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包:
``` ```swift
let alsoIncrementByTen = incrementByTen let alsoIncrementByTen = incrementByTen
alsoIncrementByTen() alsoIncrementByTen()
// 返回的值为50 // 返回的值为50
``` ```

View File

@ -1,17 +1,15 @@
> 翻译yankuangshi > 翻译yankuangshi
> 校对shinyzhu
> 校对shinyzhu
# 枚举Enumerations # 枚举Enumerations
--- ---
本页内容包含: 本页内容包含:
- [枚举语法Enumeration Syntax](#enumeration_syntax) - [枚举语法Enumeration Syntax](#enumeration_syntax)
- [匹配枚举值与`Swith`语句Matching Enumeration Values with a Switch Statement](#matching_enumeration_values_with_a_switch_statement) - [匹配枚举值与`Swith`语句Matching Enumeration Values with a Switch Statement](#matching_enumeration_values_with_a_switch_statement)
- [实例值Associated Values](#associated_values) - [实例值Associated Values](#associated_values)
- [原始值Raw Values](#raw_values) - [原始值Raw Values](#raw_values)
枚举定义了一个通用类型的一组相关的值,使你可以在你的代码中以一个安全的方式来使用这些值。 枚举定义了一个通用类型的一组相关的值,使你可以在你的代码中以一个安全的方式来使用这些值。
@ -28,38 +26,47 @@
使用`enum`关键词并且把它们的整个定义放在一对大括号内: 使用`enum`关键词并且把它们的整个定义放在一对大括号内:
enum SomeEumeration { ```swift
// enumeration definition goes here enum SomeEumeration {
} // enumeration definition goes here
}
```
以下是指南针四个方向的一个例子: 以下是指南针四个方向的一个例子:
enum CompassPoint { ```swift
case North enum CompassPoint {
case South case North
case East case South
case West case East
} case West
}
```
一个枚举中被定义的值(例如 `North``South``East``West`)是枚举的***成员值***(或者***成员***)。`case`关键词表明新的一行成员值将被定义。 一个枚举中被定义的值(例如 `North``South``East``West`)是枚举的***成员值***(或者***成员***)。`case`关键词表明新的一行成员值将被定义。
> 注意: > 注意:
> > 不像 C 和 Objective-C 一样Swift 的枚举成员在被创建时不会被赋予一个默认的整数值。在上面的`CompassPoints`例子中,`North``South``East`和`West`不是隐式的等于`0``1``2`和`3`。相反的,这些不同的枚举成员在`CompassPoint`的一种显示定义中拥有各自不同的值。
> 不像 C 和 Objective-C 一样Swift 的枚举成员在被创建时不会被赋予一个默认的整数值。在上面的`CompassPoints`例子中,`North``South``East`和`West`不是隐式的等于`0``1``2`和`3`。相反的,这些不同的枚举成员在`CompassPoint`的一种显示定义中拥有各自不同的值。
多个成员值可以出现在同一行上,用逗号隔开: 多个成员值可以出现在同一行上,用逗号隔开:
enum Planet { ```swift
case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Nepturn enum Planet {
} case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Nepturn
}
```
每个枚举定义了一个全新的类型。像 Swift 中其他类型一样,它们的名字(例如`CompassPoint``Planet`)必须以一个大写字母开头。给枚举类型起一个单数名字而不是复数名字,以便于读起来更加容易理解: 每个枚举定义了一个全新的类型。像 Swift 中其他类型一样,它们的名字(例如`CompassPoint``Planet`)必须以一个大写字母开头。给枚举类型起一个单数名字而不是复数名字,以便于读起来更加容易理解:
var directionToHead = CompassPoint.West ```swift
var directionToHead = CompassPoint.West
```
`directionToHead`的类型被推断当它被`CompassPoint`的一个可能值初始化。一旦`directionToHead`被声明为一个`CompassPoint`,你可以使用更短的点(.)语法将其设置为另一个`CompassPoint`的值: `directionToHead`的类型被推断当它被`CompassPoint`的一个可能值初始化。一旦`directionToHead`被声明为一个`CompassPoint`,你可以使用更短的点(.)语法将其设置为另一个`CompassPoint`的值:
directionToHead = .East ```swift
directionToHead = .East
```
`directionToHead`的类型已知时,当设定它的值时,你可以不再写类型名。使用显示类型的枚举值可以让代码具有更好的可读性。 `directionToHead`的类型已知时,当设定它的值时,你可以不再写类型名。使用显示类型的枚举值可以让代码具有更好的可读性。
@ -68,18 +75,20 @@
你可以匹配单个枚举值和`switch`语句: 你可以匹配单个枚举值和`switch`语句:
directionToHead = .South ```swift
switch directionToHead { directionToHead = .South
case .North: switch directionToHead {
println("Lots of planets have a north") case .North:
case .South: println("Lots of planets have a north")
println("Watch out for penguins") case .South:
case .East: println("Watch out for penguins")
println("Where the sun rises") case .East:
case .West: println("Where the sun rises")
println("Where the skies are blue") case .West:
} println("Where the skies are blue")
// 输出 "Watch out for penguins” }
// 输出 "Watch out for penguins”
```
你可以如此理解这段代码: 你可以如此理解这段代码:
@ -91,14 +100,16 @@
当不需要匹配每个枚举成员的时候,你可以提供一个默认`default`分支来涵盖所有未明确被提出的任何成员: 当不需要匹配每个枚举成员的时候,你可以提供一个默认`default`分支来涵盖所有未明确被提出的任何成员:
let somePlanet = Planet.Earth ```swift
switch somePlanet { let somePlanet = Planet.Earth
case .Earth: switch somePlanet {
println("Mostly harmless") case .Earth:
default: println("Mostly harmless")
println("Not a safe place for humans") default:
} println("Not a safe place for humans")
// 输出 "Mostly harmless” }
// 输出 "Mostly harmless”
```
<a name="associated_values"></a> <a name="associated_values"></a>
## 实例值Associated Values ## 实例值Associated Values
@ -119,10 +130,12 @@
在 Swift 中,用来定义两种商品条码的枚举是这样子的: 在 Swift 中,用来定义两种商品条码的枚举是这样子的:
enum Barcode { ```swift
case UPCA(Int, Int, Int) enum Barcode {
case QRCode(String) case UPCA(Int, Int, Int)
} case QRCode(String)
}
```
以上代码可以这么理解: 以上代码可以这么理解:
@ -132,35 +145,43 @@
然后可以使用任何一种条码类型创建新的条码,如: 然后可以使用任何一种条码类型创建新的条码,如:
var productBarcode = Barcode.UPCA(8, 85909_51226, 3) ```swift
var productBarcode = Barcode.UPCA(8, 85909_51226, 3)
```
以上例子创建了一个名为`productBarcode`的新变量,并且赋给它一个`Barcode.UPCA`的实例元组值`(8, 8590951226, 3)`。提供的“标识符”值在整数字中有一个下划线,使其便于阅读条形码。 以上例子创建了一个名为`productBarcode`的新变量,并且赋给它一个`Barcode.UPCA`的实例元组值`(8, 8590951226, 3)`。提供的“标识符”值在整数字中有一个下划线,使其便于阅读条形码。
同一个商品可以被分配给一个不同类型的条形码,如: 同一个商品可以被分配给一个不同类型的条形码,如:
productBarcode = .QRCode("ABCDEFGHIJKLMNOP") ```swift
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
```
这时,原始的`Barcode.UPCA`和其整数值被新的`Barcode.QRCode`和其字符串值所替代。条形码的常量和变量可以存储一个`.UPCA`或者一个`.QRCode`(连同它的实例值),但是在任何指定时间只能存储其中之一。 这时,原始的`Barcode.UPCA`和其整数值被新的`Barcode.QRCode`和其字符串值所替代。条形码的常量和变量可以存储一个`.UPCA`或者一个`.QRCode`(连同它的实例值),但是在任何指定时间只能存储其中之一。
像以前那样,不同的条形码类型可以使用一个 switch 语句来检查,然而这次实例值可以被提取作为 switch 语句的一部分。你可以在`switch`的 case 分支代码中提取每个实例值作为一个常量(用`let`前缀)或者作为一个变量(用`var`前缀)来使用: 像以前那样,不同的条形码类型可以使用一个 switch 语句来检查,然而这次实例值可以被提取作为 switch 语句的一部分。你可以在`switch`的 case 分支代码中提取每个实例值作为一个常量(用`let`前缀)或者作为一个变量(用`var`前缀)来使用:
switch productBarcode { ```swift
case .UPCA(let numberSystem, let identifier, let check): switch productBarcode {
println("UPC-A with value of \(numberSystem), \(identifier), \(check).") case .UPCA(let numberSystem, let identifier, let check):
case .QRCode(let productCode): println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
println("QR code with value of \(productCode).") case .QRCode(let productCode):
} println("QR code with value of \(productCode).")
// 输出 "QR code with value of ABCDEFGHIJKLMNOP.” }
// 输出 "QR code with value of ABCDEFGHIJKLMNOP.”
```
如果一个枚举成员的所有实例值被提取为常量,或者它们全部被提取为变量,为了简洁,你可以只放置一个`var`或者`let`标注在成员名称前: 如果一个枚举成员的所有实例值被提取为常量,或者它们全部被提取为变量,为了简洁,你可以只放置一个`var`或者`let`标注在成员名称前:
switch productBarcode { ```swift
case let .UPCA(numberSystem, identifier, check): switch productBarcode {
println("UPC-A with value of \(numberSystem), \(identifier), \(check).") case let .UPCA(numberSystem, identifier, check):
case let .QRCode(productCode): println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
println("QR code with value of \(productCode).") case let .QRCode(productCode):
} println("QR code with value of \(productCode).")
// 输出 "QR code with value of ABCDEFGHIJKLMNOP." }
// 输出 "QR code with value of ABCDEFGHIJKLMNOP."
```
<a name="raw_values"></a> <a name="raw_values"></a>
## 原始值Raw Values ## 原始值Raw Values
@ -169,11 +190,13 @@
这里是一个枚举成员存储原始 ASCII 值的例子: 这里是一个枚举成员存储原始 ASCII 值的例子:
enum ASCIIControlCharacter: Character { ```swift
case Tab = "\t" enum ASCIIControlCharacter: Character {
case LineFeed = "\n" case Tab = "\t"
case CarriageReturn = "\r" case LineFeed = "\n"
} case CarriageReturn = "\r"
}
```
在这里,称为`ASCIIControlCharacter`的枚举的原始值类型被定义为字符型`Character`,并被设置了一些比较常见的 ASCII 控制字符。字符值的描述请详见字符串和字符`Strings and Characters`部分。 在这里,称为`ASCIIControlCharacter`的枚举的原始值类型被定义为字符型`Character`,并被设置了一些比较常见的 ASCII 控制字符。字符值的描述请详见字符串和字符`Strings and Characters`部分。
@ -183,37 +206,46 @@
下面的枚举是对之前`Planet`这个枚举的一个细化,利用原始整型值来表示每个 planet 在太阳系中的顺序: 下面的枚举是对之前`Planet`这个枚举的一个细化,利用原始整型值来表示每个 planet 在太阳系中的顺序:
enum Planet: Int { ```swift
case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune enum Planet: Int {
} case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
```
自动递增意味着`Planet.Venus`的原始值是`2`,依次类推。 自动递增意味着`Planet.Venus`的原始值是`2`,依次类推。
使用枚举成员的`toRaw`方法可以访问该枚举成员的原始值: 使用枚举成员的`toRaw`方法可以访问该枚举成员的原始值:
let earthsOrder = Planet.Earth.toRaw() ```swift
// earthsOrder is 3 let earthsOrder = Planet.Earth.toRaw()
// earthsOrder is 3
```
使用枚举的`fromRaw`方法来试图找到具有特定原始值的枚举成员。这个例子通过原始值`7`识别`Uranus` 使用枚举的`fromRaw`方法来试图找到具有特定原始值的枚举成员。这个例子通过原始值`7`识别`Uranus`
let possiblePlanet = Planet.fromRaw(7) ```swift
// possiblePlanet is of type Planet? and equals Planet.Uranus let possiblePlanet = Planet.fromRaw(7)
// possiblePlanet is of type Planet? and equals Planet.Uranus
```
然而,并非所有可能的`Int`值都可以找到一个匹配的行星。正因为如此,`fromRaw`方法可以返回一个***可选***的枚举成员。在上面的例子中,`possiblePlanet``Planet?`类型,或“可选的`Planet`”。 然而,并非所有可能的`Int`值都可以找到一个匹配的行星。正因为如此,`fromRaw`方法可以返回一个***可选***的枚举成员。在上面的例子中,`possiblePlanet``Planet?`类型,或“可选的`Planet`”。
如果你试图寻找一个位置为9的行星通过`fromRaw`返回的可选`Planet`值将是`nil` 如果你试图寻找一个位置为9的行星通过`fromRaw`返回的可选`Planet`值将是`nil`
let positionToFind = 9 ```swift
if let somePlanet = Planet.fromRaw(positionToFind) { let positionToFind = 9
switch somePlanet { if let somePlanet = Planet.fromRaw(positionToFind) {
case .Earth: switch somePlanet {
println("Mostly harmless") case .Earth:
default: println("Mostly harmless")
println("Not a safe place for humans") default:
} println("Not a safe place for humans")
} else { }
println("There isn't a planet at position \(positionToFind)") } else {
} println("There isn't a planet at position \(positionToFind)")
// 输出 "There isn't a planet at position 9 }
// 输出 "There isn't a planet at position 9
```
这个范例使用可选绑定optional binding通过原始值`9`试图访问一个行星。`if let somePlanet = Planet.fromRaw(9)`语句获得一个可选`Planet`,如果可选`Planet`可以被获得,把`somePlanet`设置成该可选`Planet`的内容。在这个范例中,无法检索到位置为`9`的行星,所以`else`分支被执行。 这个范例使用可选绑定optional binding通过原始值`9`试图访问一个行星。`if let somePlanet = Planet.fromRaw(9)`语句获得一个可选`Planet`,如果可选`Planet`可以被获得,把`somePlanet`设置成该可选`Planet`的内容。在这个范例中,无法检索到位置为`9`的行星,所以`else`分支被执行。

View File

@ -1,35 +1,33 @@
> 翻译JaySurplus > 翻译JaySurplus
> 校对sg552
> 校对sg552
# 类和结构体 # 类和结构体
本页包含内容: 本页包含内容:
- [类和结构体对比](#comparing_classes_and_structures) - [类和结构体对比](#comparing_classes_and_structures)
- [结构体和枚举是值类型](#structures_and_enumerations_are_value_types) - [结构体和枚举是值类型](#structures_and_enumerations_are_value_types)
- [类是引用类型](#classes_are_reference_types) - [类是引用类型](#classes_are_reference_types)
- [类和结构体的选择](#choosing_between_classes_and_structures) - [类和结构体的选择](#choosing_between_classes_and_structures)
- [集合collection类型的赋值与复制行为](#assignment_and_copy_behavior_for_collection_types) - [集合collection类型的赋值与复制行为](#assignment_and_copy_behavior_for_collection_types)
类和结构体是人们构建代码所用的一种通用且灵活的构造体。为了在类和结构体中实现各种功能,我们必须要严格按照对于常量,变量以及函数所规定的语法规则来定义属性和添加方法。 类和结构体是人们构建代码所用的一种通用且灵活的构造体。为了在类和结构体中实现各种功能,我们必须要严格按照对于常量,变量以及函数所规定的语法规则来定义属性和添加方法。
与其他编程语言所不同的是Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口。 与其他编程语言所不同的是Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口。
> 注意: > 注意:
>
通常一个`类`的实例被称为`对象`。然而在Swift 中,类和结构体的关系要比在其他语言中更加的密切,本章中所讨论的大部分功能都可以用在类和结构体上。因此,我们会主要使用`实例`而不是`对象` 通常一个`类`的实例被称为`对象`。然而在Swift 中,类和结构体的关系要比在其他语言中更加的密切,本章中所讨论的大部分功能都可以用在类和结构体上。因此,我们会主要使用`实例`而不是`对象`
<a name="comparing_classes_and_structures"></a> <a name="comparing_classes_and_structures"></a>
###类和结构体对比 ###类和结构体对比
Swift 中类和结构体有很多共同点。共同处在于: Swift 中类和结构体有很多共同点。共同处在于:
* 定义属性用于储存值 * 定义属性用于储存值
* 定义方法用于提供功能 * 定义方法用于提供功能
* 定义附属脚本用于访问值 * 定义附属脚本用于访问值
* 定义构造器用于生成初始化值 * 定义构造器用于生成初始化值
* 通过扩展以增加默认实现的功能 * 通过扩展以增加默认实现的功能
* 符合协议以对某类提供标准功能 * 符合协议以对某类提供标准功能
更多信息请参见 [属性](10_Properties.html)[方法](11_Methods.html)[附属脚本](12_Subscripts.html)[初始过程](14_Initialization.html)[扩展](20_Extensions.html),和[协议](21_Protocols.html)。 更多信息请参见 [属性](10_Properties.html)[方法](11_Methods.html)[附属脚本](12_Subscripts.html)[初始过程](14_Initialization.html)[扩展](20_Extensions.html),和[协议](21_Protocols.html)。
@ -43,36 +41,38 @@ Swift 中类和结构体有很多共同点。共同处在于:
更多信息请参见[继承](http://)[类型转换](http://)[初始化](http://),和[自动引用计数](http://)。 更多信息请参见[继承](http://)[类型转换](http://)[初始化](http://),和[自动引用计数](http://)。
> 注意: > 注意:
>
结构体总是通过被复制的方式在代码中传递,因此请不要使用引用计数。 结构体总是通过被复制的方式在代码中传递,因此请不要使用引用计数。
### 定义 ### 定义
类和结构体有着类似的定义方式。我们通过关键字`class``struct`来分别表示类和结构体,并在一对大括号中定义它们的具体内容: 类和结构体有着类似的定义方式。我们通过关键字`class``struct`来分别表示类和结构体,并在一对大括号中定义它们的具体内容:
class SomeClass { ```swift
// class definition goes here class SomeClass {
} // class definition goes here
struct SomeStructure { }
// structure definition goes here struct SomeStructure {
} // structure definition goes here
}
```
> 注意: > 注意:
>
在你每次定义一个新类或者结构体的时候,实际上你是有效地定义了一个新的 Swift 类型。因此请使用 `UpperCamelCase` 这种方式来命名(如 `SomeClass``SomeStructure`以便符合标准Swift 类型的大写命名风格(如`String``Int``Bool`)。相反的,请使用`lowerCamelCase`这种方式为属性和方法命名(如`framerate``incrementCount`),以便和类区分。 在你每次定义一个新类或者结构体的时候,实际上你是有效地定义了一个新的 Swift 类型。因此请使用 `UpperCamelCase` 这种方式来命名(如 `SomeClass``SomeStructure`以便符合标准Swift 类型的大写命名风格(如`String``Int``Bool`)。相反的,请使用`lowerCamelCase`这种方式为属性和方法命名(如`framerate``incrementCount`),以便和类区分。
以下是定义结构体和定义类的示例: 以下是定义结构体和定义类的示例:
struct Resolution { ```swift
var width = 0 struct Resolution {
var heigth = 0 var width = 0
} var heigth = 0
class VideoMode { }
var resolution = Resolution() class VideoMode {
var interlaced = false var resolution = Resolution()
var frameRate = 0.0 var interlaced = false
var name: String? var frameRate = 0.0
} var name: String?
}
```
在上面的示例中我们定义了一个名为`Resolution`的结构体,用来描述一个显示器的像素分辨率。这个结构体包含了两个名为`width``height`的储存属性。储存属性是捆绑和储存在类或结构体中的常量或变量。当这两个属性被初始化为整数`0`的时候,它们会被推断为`Int`类型。 在上面的示例中我们定义了一个名为`Resolution`的结构体,用来描述一个显示器的像素分辨率。这个结构体包含了两个名为`width``height`的储存属性。储存属性是捆绑和储存在类或结构体中的常量或变量。当这两个属性被初始化为整数`0`的时候,它们会被推断为`Int`类型。
@ -83,8 +83,10 @@ Swift 中类和结构体有很多共同点。共同处在于:
生成结构体和类实例的语法非常相似: 生成结构体和类实例的语法非常相似:
let someResolution = Resolution() ```swift
let someVideoMode = VideoMode() let someResolution = Resolution()
let someVideoMode = VideoMode()
```
结构体和类都使用构造器语法来生成新的实例。构造器语法的最简单形式是在结构体或者类的类型名称后跟随一个空括弧,如`Resolution()``VideoMode()`。通过这种方式所创建的类或者结构体实例,其属均会被初始化为默认值。[构造过程](14_Initialization.html)章节会对类和结构体的初始化进行更详细的讨论。 结构体和类都使用构造器语法来生成新的实例。构造器语法的最简单形式是在结构体或者类的类型名称后跟随一个空括弧,如`Resolution()``VideoMode()`。通过这种方式所创建的类或者结构体实例,其属均会被初始化为默认值。[构造过程](14_Initialization.html)章节会对类和结构体的初始化进行更详细的讨论。
@ -92,32 +94,38 @@ Swift 中类和结构体有很多共同点。共同处在于:
### 属性访问 ### 属性访问
通过使用*点语法**dot syntax*,你可以访问实例中所含有的属性。其语法规则是,实例名后面紧跟属性名,两者通过点号(.)连接: 通过使用*点语法**dot syntax*,你可以访问实例中所含有的属性。其语法规则是,实例名后面紧跟属性名,两者通过点号(.)连接:
println("The width of someResolution is \(someResolution.width)") ```swift
// 输出 "The width of someResolution is 0" println("The width of someResolution is \(someResolution.width)")
// 输出 "The width of someResolution is 0"
```
在上面的例子中,`someResolution.width`引用`someResolution``width`属性,返回`width`的初始值`0` 在上面的例子中,`someResolution.width`引用`someResolution``width`属性,返回`width`的初始值`0`
你也可以访问子属性,如何`VideoMode``Resolution`属性的`width`属性: 你也可以访问子属性,如何`VideoMode``Resolution`属性的`width`属性:
println("The width of someVideoMode is \(someVideoMode.resolution.width)") ```swift
// 输出 "The width of someVideoMode is 0" println("The width of someVideoMode is \(someVideoMode.resolution.width)")
// 输出 "The width of someVideoMode is 0"
```
你也可以使用点语法为属性变量赋值: 你也可以使用点语法为属性变量赋值:
someVideoMode.resolution.width = 12880 ```swift
println("The width of someVideoMode is now \(someVideoMode.resolution.width)") someVideoMode.resolution.width = 12880
// 输出 "The width of someVideoMode is now 1280" println("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// 输出 "The width of someVideoMode is now 1280"
```
> 注意: > 注意:
>
与 Objective-C 语言不同的是Swift 允许直接设置结构体属性的子属性。上面的最后一个例子,就是直接设置了`someVideoMode``resolution`属性的`width`这个子属性,以上操作并不需要从新设置`resolution`属性。 与 Objective-C 语言不同的是Swift 允许直接设置结构体属性的子属性。上面的最后一个例子,就是直接设置了`someVideoMode``resolution`属性的`width`这个子属性,以上操作并不需要从新设置`resolution`属性。
### 结构体类型的成员逐一构造器 ### 结构体类型的成员逐一构造器(Memberwise Initializers for structure Types)
//Memberwise Initializers for structure Types
所有结构体都有一个自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器之中: 所有结构体都有一个自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器之中:
let vga = resolution(width:640, heigth: 480) ```swift
let vga = resolution(width:640, heigth: 480)
```
与结构体不同,类实例没有默认的成员逐一构造器。[构造过程](14_Initialization.html)章节会对构造器进行更详细的讨论。 与结构体不同,类实例没有默认的成员逐一构造器。[构造过程](14_Initialization.html)章节会对构造器进行更详细的讨论。
@ -132,8 +140,10 @@ Swift 中类和结构体有很多共同点。共同处在于:
请看下面这个示例,其使用了前一个示例中`Resolution`结构体: 请看下面这个示例,其使用了前一个示例中`Resolution`结构体:
let hd = Resolution(width: 1920, height: 1080) ```swift
var cinema = hd let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
```
在以上示例中,声明了一个名为`hd`的常量其值为一个初始化为全高清视频分辨率1920 像素宽1080 像素高)的`Resolution`实例。 在以上示例中,声明了一个名为`hd`的常量其值为一个初始化为全高清视频分辨率1920 像素宽1080 像素高)的`Resolution`实例。
@ -141,32 +151,40 @@ Swift 中类和结构体有很多共同点。共同处在于:
下面为了符合数码影院放映的需求2048 像素宽1080 像素高),`cinema``width`属性需要作如下修改: 下面为了符合数码影院放映的需求2048 像素宽1080 像素高),`cinema``width`属性需要作如下修改:
cinema.width = 2048 ```swift
cinema.width = 2048
```
这里,将会显示`cinema``width`属性确已改为了`2048` 这里,将会显示`cinema``width`属性确已改为了`2048`
println("cinema is now \(cinema.width) pixels wide") ```swift
// 输出 "cinema is now 2048 pixels wide" println("cinema is now \(cinema.width) pixels wide")
// 输出 "cinema is now 2048 pixels wide"
```
然而,初始的`hd`实例中`width`属性还是`1920` 然而,初始的`hd`实例中`width`属性还是`1920`
println("hd is still \(hd.width ) pixels wide") ```swift
// 输出 "hd is still 1920 pixels wide" println("hd is still \(hd.width ) pixels wide")
// 输出 "hd is still 1920 pixels wide"
```
在将`hd`赋予给`cinema`的时候,实际上是将`hd`中所储存的`值values`进行拷贝,然后将拷贝的数据储存到新的`cinema`实例中。结果就是两个完全独立的实例碰巧包含有相同的数值。由于两者相互独立,因此将`cinema``width`修改为`2048`并不会影响`hd`中的宽width 在将`hd`赋予给`cinema`的时候,实际上是将`hd`中所储存的`值values`进行拷贝,然后将拷贝的数据储存到新的`cinema`实例中。结果就是两个完全独立的实例碰巧包含有相同的数值。由于两者相互独立,因此将`cinema``width`修改为`2048`并不会影响`hd`中的宽width
枚举也遵循相同的行为准则: 枚举也遵循相同的行为准则:
enum CompassPoint { ```swift
case North, South, East, West enum CompassPoint {
} case North, South, East, West
var currentDirection = CompassPoint.West }
let rememberedDirection = currentDirection var currentDirection = CompassPoint.West
currentDirection = .East let rememberedDirection = currentDirection
if rememberDirection == .West { currentDirection = .East
println("The remembered direction is still .West") if rememberDirection == .West {
} println("The remembered direction is still .West")
// 输出 "The remembered direction is still .West" }
// 输出 "The remembered direction is still .West"
```
上例中`rememberedDirection`被赋予了`currentDirection`的值value实际上它被赋予的是值value的一个拷贝。赋值过程结束后再修改`currentDirection`的值并不影响`rememberedDirection`所储存的原始值value的拷贝。 上例中`rememberedDirection`被赋予了`currentDirection`的值value实际上它被赋予的是值value的一个拷贝。赋值过程结束后再修改`currentDirection`的值并不影响`rememberedDirection`所储存的原始值value的拷贝。
@ -176,25 +194,31 @@ Swift 中类和结构体有很多共同点。共同处在于:
请看下面这个示例,其使用了之前定义的`VideoMode`类: 请看下面这个示例,其使用了之前定义的`VideoMode`类:
let tenEighty = VideoMode() ```swift
tenEighty.resolution = hd let tenEighty = VideoMode()
tenEighty.interlaced = true tenEighty.resolution = hd
tenEighty.name = "1080i" tenEighty.interlaced = true
tenEighty.frameRate = 25.0 tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
```
以上示例中,声明了一个名为`tenEighty`的常量,其引用了一个`VideoMode`类的新实例。在之前的示例中这个视频模式video mode被赋予了HD分辨率1920*1080的一个拷贝`hd`。同时设置为交错interlaced,命名为`“1080i”`。最后,其帧率是`25.0`帧每秒。 以上示例中,声明了一个名为`tenEighty`的常量,其引用了一个`VideoMode`类的新实例。在之前的示例中这个视频模式video mode被赋予了HD分辨率1920*1080的一个拷贝`hd`。同时设置为交错interlaced,命名为`“1080i”`。最后,其帧率是`25.0`帧每秒。
然后,`tenEighty` 被赋予名为`alsoTenEighty`的新常量,同时对`alsoTenEighty`的帧率进行修改: 然后,`tenEighty` 被赋予名为`alsoTenEighty`的新常量,同时对`alsoTenEighty`的帧率进行修改:
let alsoTenEighty = tenEighty ```swift
alsoTenEighty.frameRate = 30.0 let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
```
因为类是引用类型,所以`tenEight``alsoTenEight`实际上引用的是相同的`VideoMode`实例。换句话说,它们只是同一个实例的两种叫法。 因为类是引用类型,所以`tenEight``alsoTenEight`实际上引用的是相同的`VideoMode`实例。换句话说,它们只是同一个实例的两种叫法。
下面,通过查看`tenEighty``frameRate`属性,我们会发现它正确的显示了基本`VideoMode`实例的新帧率,其值为`30.0` 下面,通过查看`tenEighty``frameRate`属性,我们会发现它正确的显示了基本`VideoMode`实例的新帧率,其值为`30.0`
println("The frameRate property of tenEighty is now \(tenEighty.frameRate)") ```swift
// 输出 "The frameRate property of theEighty is now 30.0" println("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// 输出 "The frameRate property of theEighty is now 30.0"
```
需要注意的是`tenEighty``alsoTenEighty`被声明为*常量constants*而不是变量。然而你依然可以改变`tenEighty.frameRate``alsoTenEighty.frameRate`,因为这两个常量本身不会改变。它们并不`储存`这个`VideoMode`实例,在后台仅仅是对`VideoMode`实例的引用。所以,改变的是被引用的基础`VideoMode``frameRate`参数,而不改变常量的值。 需要注意的是`tenEighty``alsoTenEighty`被声明为*常量constants*而不是变量。然而你依然可以改变`tenEighty.frameRate``alsoTenEighty.frameRate`,因为这两个常量本身不会改变。它们并不`储存`这个`VideoMode`实例,在后台仅仅是对`VideoMode`实例的引用。所以,改变的是被引用的基础`VideoMode``frameRate`参数,而不改变常量的值。
@ -209,10 +233,12 @@ Swift 中类和结构体有很多共同点。共同处在于:
以下是运用这两个运算符检测两个常量或者变量是否引用同一个实例: 以下是运用这两个运算符检测两个常量或者变量是否引用同一个实例:
if tenEighty === alsoTenTighty { ```swift
println("tenTighty and alsoTenEighty refer to the same Resolution instance.") if tenEighty === alsoTenTighty {
} println("tenTighty and alsoTenEighty refer to the same Resolution instance.")
//输出 "tenEighty and alsoTenEighty refer to the same Resolution instance." }
//输出 "tenEighty and alsoTenEighty refer to the same Resolution instance."
```
请注意“等价于”(用三个等号表示,=== 与“等于”(用两个等号表示,==)的不同: 请注意“等价于”(用三个等号表示,=== 与“等于”(用两个等号表示,==)的不同:
@ -251,8 +277,7 @@ Swift 中`数组Array`和`字典Dictionary`类型均以结构体的
以下对`数组``结构体`的行为描述与对`NSArray``NSDictionary`的行为描述在本质上不同,后者是以类的形式实现,前者是以结构体的形式实现。`NSArray``NSDictionary`实例总是以对已有实例引用,而不是拷贝的方式被赋值和传递。 以下对`数组``结构体`的行为描述与对`NSArray``NSDictionary`的行为描述在本质上不同,后者是以类的形式实现,前者是以结构体的形式实现。`NSArray``NSDictionary`实例总是以对已有实例引用,而不是拷贝的方式被赋值和传递。
> 注意: > 注意:
>
以下是对于数组,字典,字符串和其它值的`拷贝`的描述。 以下是对于数组,字典,字符串和其它值的`拷贝`的描述。
在你的代码中,拷贝好像是确实是在有拷贝行为的地方产生过。然而,在 Swift 的后台中,只有确有必要,`实际actual`拷贝才会被执行。Swift 管理所有的值拷贝以确保性能最优化的性能,所以你也没有必要去避免赋值以保证最优性能。(实际赋值由系统管理优化) 在你的代码中,拷贝好像是确实是在有拷贝行为的地方产生过。然而,在 Swift 的后台中,只有确有必要,`实际actual`拷贝才会被执行。Swift 管理所有的值拷贝以确保性能最优化的性能,所以你也没有必要去避免赋值以保证最优性能。(实际赋值由系统管理优化)
@ -263,16 +288,20 @@ Swift 中`数组Array`和`字典Dictionary`类型均以结构体的
下面的示例定义了一个名为`ages`的字典,其中储存了四个人的名字和年龄。`ages`字典被赋予了一个名为`copiedAges`的新变量,同时`ages`在赋值的过程中被拷贝。赋值结束后,`ages``copiedAges`成为两个相互独立的字典。 下面的示例定义了一个名为`ages`的字典,其中储存了四个人的名字和年龄。`ages`字典被赋予了一个名为`copiedAges`的新变量,同时`ages`在赋值的过程中被拷贝。赋值结束后,`ages``copiedAges`成为两个相互独立的字典。
var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19] ```swift
var copiedAges = ages var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19]
var copiedAges = ages
```
这个字典的键keys`字符串String`类型values`整Int`类型。这两种类型在Swift 中都是值类型value types所以当字典被拷贝时两者都会被拷贝。 这个字典的键keys`字符串String`类型values`整Int`类型。这两种类型在Swift 中都是值类型value types所以当字典被拷贝时两者都会被拷贝。
我们可以通过改变一个字典中的年龄值age value检查另一个字典中所对应的值来证明`ages`字典确实是被拷贝了。如果在`copiedAges`字典中将`Peter`的值设为`24`,那么`ages`字典仍然会返回修改前的值`23` 我们可以通过改变一个字典中的年龄值age value检查另一个字典中所对应的值来证明`ages`字典确实是被拷贝了。如果在`copiedAges`字典中将`Peter`的值设为`24`,那么`ages`字典仍然会返回修改前的值`23`
copiedAges["Peter"] = 24 ```swift
println(ages["Peter"]) copiedAges["Peter"] = 24
// 输出 "23" println(ages["Peter"])
// 输出 "23"
```
### 数组的赋值和拷贝行为 ### 数组的赋值和拷贝行为
@ -284,42 +313,50 @@ Swift 中`数组Array`和`字典Dictionary`类型均以结构体的
下面的示例将一个`整数Int`数组赋给了一个名为`a`的变量,继而又被赋给了变量`b`和`c` 下面的示例将一个`整数Int`数组赋给了一个名为`a`的变量,继而又被赋给了变量`b`和`c`
var a = [1, 2, 3] ```swift
var b = a var a = [1, 2, 3]
var c = a var b = a
var c = a
```
我们可以在`a`,`b`,`c`上使用下标语法以得到数组的第一个元素: 我们可以在`a`,`b`,`c`上使用下标语法以得到数组的第一个元素:
println(a[0]) ```swift
// 1 println(a[0])
println(b[0]) // 1
// 1 println(b[0])
println(c[0]) // 1
// 1 println(c[0])
// 1
```
如果通过下标语法修改数组中某一元素的值,那么`a`,`b`,`c`中的相应值都会发生改变。请注意当你用下标语法修改某一值时,并没有拷贝行为伴随发生,因为下表语法修改值时没有改变数组长度的可能: 如果通过下标语法修改数组中某一元素的值,那么`a`,`b`,`c`中的相应值都会发生改变。请注意当你用下标语法修改某一值时,并没有拷贝行为伴随发生,因为下表语法修改值时没有改变数组长度的可能:
a[0] = 42 ```swift
println(a[0]) a[0] = 42
// 42 println(a[0])
println(b[0]) // 42
// 42 println(b[0])
println(c[0]) // 42
// 42 println(c[0])
// 42
```
然而,当你给`a`附加新元素时,数组的长度`会`改变。 然而,当你给`a`附加新元素时,数组的长度`会`改变。
当附加元素这一事件发生时Swift 会创建这个数组的一个拷贝。从此以后,`a`将会是原数组的一个独立拷贝。 当附加元素这一事件发生时Swift 会创建这个数组的一个拷贝。从此以后,`a`将会是原数组的一个独立拷贝。
拷贝发生后,如果再修改`a`中元素值的话,`a`将会返回与`b``c`不同的结果,因为后两者引用的是原来的数组: 拷贝发生后,如果再修改`a`中元素值的话,`a`将会返回与`b``c`不同的结果,因为后两者引用的是原来的数组:
a.append(4) ```swift
a[0] = 777 a.append(4)
println(a[0]) a[0] = 777
// 777 println(a[0])
println(b[0]) // 777
// 42 println(b[0])
println(c[0]) // 42
// 42 println(c[0])
// 42
```
### 确保数组的唯一性 ### 确保数组的唯一性
在操作一个数组,或将其传递给函数以及方法调用之前是很有必要先确定这个数组是有一个唯一拷贝的。通过在数组变量上调用`unshare`方法来确定数组引用的唯一性。(当数组赋给常量时,不能调用`unshare`方法) 在操作一个数组,或将其传递给函数以及方法调用之前是很有必要先确定这个数组是有一个唯一拷贝的。通过在数组变量上调用`unshare`方法来确定数组引用的唯一性。(当数组赋给常量时,不能调用`unshare`方法)
@ -328,17 +365,21 @@ Swift 中`数组Array`和`字典Dictionary`类型均以结构体的
在上一个示例的最后,`b``c`都引用了同一个数组。此时在`b`上调用`unshare`方法则会将`b`变成一个唯一个拷贝: 在上一个示例的最后,`b``c`都引用了同一个数组。此时在`b`上调用`unshare`方法则会将`b`变成一个唯一个拷贝:
b.unshare() ```swift
b.unshare()
```
`unshare`方法调用后再修改`b`中第一个元素的值,这三个数组(`a`,`b`,`c`)会返回不同的三个值: `unshare`方法调用后再修改`b`中第一个元素的值,这三个数组(`a`,`b`,`c`)会返回不同的三个值:
b[0] = -105 ```swift
println(a[0]) b[0] = -105
// 77 println(a[0])
println(b[0]) // 77
// -105 println(b[0])
println(c[0]) // -105
// 42 println(c[0])
// 42
```
### 判定两个数组是否共用相同元素 ### 判定两个数组是否共用相同元素
@ -347,22 +388,28 @@ Swift 中`数组Array`和`字典Dictionary`类型均以结构体的
下面这个示例使用了“等同identical to” 运算符(=== 来判定`b``c`是否共用相同的数组元素: 下面这个示例使用了“等同identical to” 运算符(=== 来判定`b``c`是否共用相同的数组元素:
if b === c { ```swift
println("b and c still share the same array elements.") if b === c {
} else { println("b and c still share the same array elements.")
println("b and c now refer to two independent sets of array elements.") } else {
} println("b and c now refer to two independent sets of array elements.")
}
```
// 输出 "b and c now refer totwo independent sets of array elements." ```swift
// 输出 "b and c now refer totwo independent sets of array elements."
```
此外,我们还可以使用恒等运算符来判定两个子数组是否共用相同的元素。下面这个示例中,比较了`b`的两个相等的子数组,并且确定了这两个子数组都引用相同的元素: 此外,我们还可以使用恒等运算符来判定两个子数组是否共用相同的元素。下面这个示例中,比较了`b`的两个相等的子数组,并且确定了这两个子数组都引用相同的元素:
if b[0...1] === b[0...1] { ```swift
println("These two subarrays share the same elements.") if b[0...1] === b[0...1] {
} else { println("These two subarrays share the same elements.")
println("These two subarrays do not share the same elements.") } else {
} println("These two subarrays do not share the same elements.")
// 输出 "These two subarrays share the same elements." }
// 输出 "These two subarrays share the same elements."
```
### 强制复制数组 ### 强制复制数组
@ -370,15 +417,19 @@ Swift 中`数组Array`和`字典Dictionary`类型均以结构体的
下面这个示例中定义了一个`names`数组,其包含了七个人名。还定义了一个`copiedNames`变量,用以储存在`names`上调用`copy`方法所返回的结果: 下面这个示例中定义了一个`names`数组,其包含了七个人名。还定义了一个`copiedNames`变量,用以储存在`names`上调用`copy`方法所返回的结果:
var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"] ```swift
var copiedNames = names.copy() var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"]
var copiedNames = names.copy()
```
我们可以通过修改一个数组中某元素,并且检查另一个数组中对应元素的方法来判定`names`数组确已被复制。如果你将`copiedNames`中第一个元素从"`Mohsen`"修改为"`Mo`",则`names`数组返回的仍是拷贝发生前的"`Mohsen`" 我们可以通过修改一个数组中某元素,并且检查另一个数组中对应元素的方法来判定`names`数组确已被复制。如果你将`copiedNames`中第一个元素从"`Mohsen`"修改为"`Mo`",则`names`数组返回的仍是拷贝发生前的"`Mohsen`"
copiedName[0] = "Mo" ```swift
println(name[0]) copiedName[0] = "Mo"
// 输出 "Mohsen" println(name[0])
// 输出 "Mohsen"
```
> 注意: > 注意:
>
如果你仅需要确保你对数组的引用是唯一引用,请调用`unshare`方法,而不是`copy`方法。`unshare`方法仅会在确有必要时才会创建数组拷贝。`copy`方法会在任何时候都创建一个新的拷贝,即使引用已经是唯一引用。 如果你仅需要确保你对数组的引用是唯一引用,请调用`unshare`方法,而不是`copy`方法。`unshare`方法仅会在确有必要时才会创建数组拷贝。`copy`方法会在任何时候都创建一个新的拷贝,即使引用已经是唯一引用。

View File

@ -1,9 +1,7 @@
> 翻译shinyzhu > 翻译shinyzhu
> 校对pp-prog
> 校对pp-prog
# 属性 (Properties) # 属性 (Properties)
--- ---
本页包含内容: 本页包含内容:
@ -29,7 +27,7 @@
下面的例子定义了一个名为`FixedLengthRange`的结构体,他描述了一个在创建后无法修改值域宽度的区间: 下面的例子定义了一个名为`FixedLengthRange`的结构体,他描述了一个在创建后无法修改值域宽度的区间:
``` ```swift
struct FixedLengthRange { struct FixedLengthRange {
var firstValue: Int var firstValue: Int
let length: Int let length: Int
@ -38,7 +36,6 @@ var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// 该区间表示整数012 // 该区间表示整数012
rangeOfThreeItems.firstValue = 6 rangeOfThreeItems.firstValue = 6
// 该区间现在表示整数678 // 该区间现在表示整数678
``` ```
`FixedLengthRange`的实例包含一个名为`firstValue`的变量存储属性和一个名为`length`的常量存储属性。在上面的例子中,`length`在创建实例的时候被赋值,因为它是一个常量存储属性,所以之后无法修改它的值。 `FixedLengthRange`的实例包含一个名为`firstValue`的变量存储属性和一个名为`length`的常量存储属性。在上面的例子中,`length`在创建实例的时候被赋值,因为它是一个常量存储属性,所以之后无法修改它的值。
@ -48,12 +45,11 @@ rangeOfThreeItems.firstValue = 6
如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性: 如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性:
``` ```swift
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// 该区间表示整数0123 // 该区间表示整数0123
rangeOfFourItems.firstValue = 6 rangeOfFourItems.firstValue = 6
// 尽管 firstValue 是个变量属性,这里还是会报错 // 尽管 firstValue 是个变量属性,这里还是会报错
``` ```
因为`rangeOfFourItems`声明成了常量(用`let`关键字),即使`firstValue`是一个变量属性,也无法再修改它了。 因为`rangeOfFourItems`声明成了常量(用`let`关键字),即使`firstValue`是一个变量属性,也无法再修改它了。
@ -67,15 +63,14 @@ rangeOfFourItems.firstValue = 6
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用`@lazy`来标示一个延迟存储属性。 延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用`@lazy`来标示一个延迟存储属性。
> 注意: > 注意:
> > 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
延迟属性很有用,当属性的值依赖于在实例的构造过程结束前无法知道具体值的外部因素时,或者当属性的值需要复杂或大量计算时,可以只在需要的时候来计算它。 延迟属性很有用,当属性的值依赖于在实例的构造过程结束前无法知道具体值的外部因素时,或者当属性的值需要复杂或大量计算时,可以只在需要的时候来计算它。
下面的例子使用了延迟存储属性来避免复杂类的不必要的初始化。例子中定义了`DataImporter``DataManager`两个类,下面是部分代码: 下面的例子使用了延迟存储属性来避免复杂类的不必要的初始化。例子中定义了`DataImporter``DataManager`两个类,下面是部分代码:
``` ```swift
class DataImporter { class DataImporter {
/* /*
DataImporter 是一个将外部文件中的数据导入的类。 DataImporter 是一个将外部文件中的数据导入的类。
@ -95,7 +90,6 @@ let manager = DataManager()
manager.data += "Some data" manager.data += "Some data"
manager.data += "Some more data" manager.data += "Some more data"
// DataImporter 实例的 importer 属性还没有被创建 // DataImporter 实例的 importer 属性还没有被创建
``` ```
`DataManager`类包含一个名为`data`的存储属性,初始值是一个空的字符串(`String`)数组。虽然没有写出全部代码,`DataManager`类的目的是管理和提供对这个字符串数组的访问。 `DataManager`类包含一个名为`data`的存储属性,初始值是一个空的字符串(`String`)数组。虽然没有写出全部代码,`DataManager`类的目的是管理和提供对这个字符串数组的访问。
@ -106,12 +100,12 @@ manager.data += "Some more data"
由于使用了`@lazy``importer`属性只有在第一次被访问的时候才被创建。比如访问它的属性`fileName`时: 由于使用了`@lazy``importer`属性只有在第一次被访问的时候才被创建。比如访问它的属性`fileName`时:
``` ```swift
println(manager.importer.fileName) println(manager.importer.fileName)
// DataImporter 实例的 importer 属性现在被创建了 // DataImporter 实例的 importer 属性现在被创建了
// 输出 "data.txt” // 输出 "data.txt”
``` ```
<a name="stored_properties_and_instance_variables"></a> <a name="stored_properties_and_instance_variables"></a>
### 存储属性和实例变量 ### 存储属性和实例变量
@ -125,7 +119,7 @@ Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属
除存储属性外,类、结构体和枚举可以定义*计算属性*,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。 除存储属性外,类、结构体和枚举可以定义*计算属性*,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。
``` ```swift
struct Point { struct Point {
var x = 0.0, y = 0.0 var x = 0.0, y = 0.0
} }
@ -153,7 +147,6 @@ let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0) square.center = Point(x: 15.0, y: 15.0)
println("square.origin is now at (\(square.origin.x), \(square.origin.y))") println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// 输出 "square.origin is now at (10.0, 10.0)” // 输出 "square.origin is now at (10.0, 10.0)”
``` ```
这个例子定义了 3 个几何形状的结构体: 这个例子定义了 3 个几何形状的结构体:
@ -177,7 +170,7 @@ println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称`newValue`。下面是使用了便捷 setter 声明的`Rect`结构体代码: 如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称`newValue`。下面是使用了便捷 setter 声明的`Rect`结构体代码:
``` ```swift
struct AlternativeRect { struct AlternativeRect {
var origin = Point() var origin = Point()
var size = Size() var size = Size()
@ -193,20 +186,19 @@ struct AlternativeRect {
} }
} }
} }
``` ```
<a name="readonly_computed_properties"></a> <a name="readonly_computed_properties"></a>
### 只读计算属性 ### 只读计算属性
只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。 只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。
> 注意: > 注意:
> > 必须使用`var`关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。
> 必须使用`var`关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。
只读计算属性的声明可以去掉`get`关键字和花括号: 只读计算属性的声明可以去掉`get`关键字和花括号:
``` ```swift
struct Cuboid { struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0 var width = 0.0, height = 0.0, depth = 0.0
var volume: Double { var volume: Double {
@ -216,7 +208,6 @@ struct Cuboid {
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0) let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// 输出 "the volume of fourByFiveByTwo is 40.0" // 输出 "the volume of fourByFiveByTwo is 40.0"
``` ```
这个例子定义了一个名为`Cuboid`的结构体,表示三维空间的立方体,包含`width``height``depth`属性,还有一个名为`volume`的只读计算属性用来返回立方体的体积。设置`volume`的值毫无意义,因为通过`width``height``depth`就能算出`volume`。然而,`Cuboid`提供一个只读计算属性来让外部用户直接获取体积是很有用的。 这个例子定义了一个名为`Cuboid`的结构体,表示三维空间的立方体,包含`width``height``depth`属性,还有一个名为`volume`的只读计算属性用来返回立方体的体积。设置`volume`的值毫无意义,因为通过`width``height``depth`就能算出`volume`。然而,`Cuboid`提供一个只读计算属性来让外部用户直接获取体积是很有用的。
@ -228,9 +219,8 @@ println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
可以为除了延迟存储属性之外的其他存储属性添加属性监视器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性监视器。属性重载请参考[继承](chapter/13_Inheritance.html)一章的[重载](chapter/13_Inheritance.html#overriding)。 可以为除了延迟存储属性之外的其他存储属性添加属性监视器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性监视器。属性重载请参考[继承](chapter/13_Inheritance.html)一章的[重载](chapter/13_Inheritance.html#overriding)。
> 注意: > 注意:
> > 不需要为无法重载的计算属性添加属性监视器,因为可以通过 setter 直接监控和响应值的变化。
> 不需要为无法重载的计算属性添加属性监视器,因为可以通过 setter 直接监控和响应值的变化。
可以为属性添加如下的一个或全部监视器: 可以为属性添加如下的一个或全部监视器:
@ -241,13 +231,12 @@ println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
类似地,`didSet`监视器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名`oldValue` 类似地,`didSet`监视器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名`oldValue`
> 注意: > 注意:
> > `willSet`和`didSet`监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用。
> `willSet`和`didSet`监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用。
这里是一个`willSet``didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数,可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。 这里是一个`willSet``didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数,可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。
``` ```swift
class StepCounter { class StepCounter {
var totalSteps: Int = 0 { var totalSteps: Int = 0 {
willSet(newTotalSteps) { willSet(newTotalSteps) {
@ -270,7 +259,6 @@ stepCounter.totalSteps = 360
stepCounter.totalSteps = 896 stepCounter.totalSteps = 896
// About to set totalSteps to 896 // About to set totalSteps to 896
// Added 536 steps // Added 536 steps
``` ```
`StepCounter`类定义了一个`Int`类型的属性`totalSteps`,它是一个存储属性,包含`willSet``didSet`监视器。 `StepCounter`类定义了一个`Int`类型的属性`totalSteps`,它是一个存储属性,包含`willSet``didSet`监视器。
@ -281,9 +269,8 @@ stepCounter.totalSteps = 896
`didSet`监视器在`totalSteps`的值改变后被调用,它把新的值和旧的值进行对比,如果总的步数增加了,就输出一个消息表示增加了多少步。`didSet`没有提供自定义名称,所以默认值`oldValue`表示旧值的参数名。 `didSet`监视器在`totalSteps`的值改变后被调用,它把新的值和旧的值进行对比,如果总的步数增加了,就输出一个消息表示增加了多少步。`didSet`没有提供自定义名称,所以默认值`oldValue`表示旧值的参数名。
> 注意: > 注意:
> > 如果在`didSet`监视器里为属性赋值,这个值会替换监视器之前设置的值。
> 如果在`didSet`监视器里为属性赋值,这个值会替换监视器之前设置的值。
<a name="global_and_local_variables"></a> <a name="global_and_local_variables"></a>
##全局变量和局部变量 ##全局变量和局部变量
@ -294,11 +281,9 @@ stepCounter.totalSteps = 896
另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义监视器,计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。 另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义监视器,计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。
> 注意: > 注意:
> > 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`@lazy`特性。
> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`@lazy`特性 > 局部范围的常量或变量不会延迟计算。
>
> 局部范围的常量或变量不会延迟计算。
<a name="type_properties"></a> <a name="type_properties"></a>
##类型属性 ##类型属性
@ -313,9 +298,8 @@ stepCounter.totalSteps = 896
值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样定义成变量属性。 值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样定义成变量属性。
> 注意: > 注意:
> > 跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。
> 跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。
<a name="type_property_syntax"></a> <a name="type_property_syntax"></a>
###类型属性语法 ###类型属性语法
@ -324,7 +308,7 @@ stepCounter.totalSteps = 896
使用关键字`static`来定义值类型的类型属性,关键字`class`来为类class定义类型属性。下面的例子演示了存储型和计算型类型属性的语法 使用关键字`static`来定义值类型的类型属性,关键字`class`来为类class定义类型属性。下面的例子演示了存储型和计算型类型属性的语法
``` ```swift
struct SomeStructure { struct SomeStructure {
static var storedTypeProperty = "Some value." static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int { static var computedTypeProperty: Int {
@ -342,19 +326,17 @@ class SomeClass {
// 这里返回一个 Int 值 // 这里返回一个 Int 值
} }
} }
``` ```
> 注意: > 注意:
> > 例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。
> 例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。
<a name="querying_and_setting_type_properties"></a> <a name="querying_and_setting_type_properties"></a>
###获取和设置类型属性的值 ###获取和设置类型属性的值
跟实例的属性一样,类型属性的访问也是通过点运算符来进行,但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如: 跟实例的属性一样,类型属性的访问也是通过点运算符来进行,但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如:
``` ```swift
println(SomeClass.computedTypeProperty) println(SomeClass.computedTypeProperty)
// 输出 "42" // 输出 "42"
@ -363,7 +345,6 @@ println(SomeStructure.storedTypeProperty)
SomeStructure.storedTypeProperty = "Another value." SomeStructure.storedTypeProperty = "Another value."
println(SomeStructure.storedTypeProperty) println(SomeStructure.storedTypeProperty)
// 输出 "Another value.” // 输出 "Another value.”
``` ```
下面的例子定义了一个结构体,使用两个存储型类型属性来表示多个声道的声音电平值,每个声道有一个 0 到 10 之间的整数表示声音电平值。 下面的例子定义了一个结构体,使用两个存储型类型属性来表示多个声道的声音电平值,每个声道有一个 0 到 10 之间的整数表示声音电平值。
@ -374,7 +355,7 @@ println(SomeStructure.storedTypeProperty)
上面所描述的声道模型使用`AudioChannel`结构体来表示: 上面所描述的声道模型使用`AudioChannel`结构体来表示:
``` ```swift
struct AudioChannel { struct AudioChannel {
static let thresholdLevel = 10 static let thresholdLevel = 10
static var maxInputLevelForAllChannels = 0 static var maxInputLevelForAllChannels = 0
@ -391,7 +372,6 @@ struct AudioChannel {
} }
} }
} }
``` ```
结构`AudioChannel`定义了 2 个存储型类型属性来实现上述功能。第一个是`thresholdLevel`,表示声音电平的最大上限阈值,它是一个取值为 10 的常量,对所有实例都可见,如果声音电平高于 10则取最大上限值 10见后面描述 结构`AudioChannel`定义了 2 个存储型类型属性来实现上述功能。第一个是`thresholdLevel`,表示声音电平的最大上限阈值,它是一个取值为 10 的常量,对所有实例都可见,如果声音电平高于 10则取最大上限值 10见后面描述
@ -405,36 +385,32 @@ struct AudioChannel {
- 如果`currentLevel`的新值大于允许的阈值`thresholdLevel`,属性监视器将`currentLevel`的值限定为阈值`thresholdLevel` - 如果`currentLevel`的新值大于允许的阈值`thresholdLevel`,属性监视器将`currentLevel`的值限定为阈值`thresholdLevel`
- 如果修正后的`currentLevel`值大于任何之前任意`AudioChannel`实例中的值,属性监视器将新值保存在静态属性`maxInputLevelForAllChannels`中。 - 如果修正后的`currentLevel`值大于任何之前任意`AudioChannel`实例中的值,属性监视器将新值保存在静态属性`maxInputLevelForAllChannels`中。
> 注意: > 注意:
> > 在第一个检查过程中,`didSet`属性监视器将`currentLevel`设置成了不同的值,但这时不会再次调用属性监视器。
> 在第一个检查过程中,`didSet`属性监视器将`currentLevel`设置成了不同的值,但这时不会再次调用属性监视器。
可以使用结构体`AudioChannel`来创建表示立体声系统的两个声道`leftChannel``rightChannel` 可以使用结构体`AudioChannel`来创建表示立体声系统的两个声道`leftChannel``rightChannel`
``` ```swift
var leftChannel = AudioChannel() var leftChannel = AudioChannel()
var rightChannel = AudioChannel() var rightChannel = AudioChannel()
``` ```
如果将左声道的电平设置成 7类型属性`maxInputLevelForAllChannels`也会更新成 7 如果将左声道的电平设置成 7类型属性`maxInputLevelForAllChannels`也会更新成 7
``` ```swift
leftChannel.currentLevel = 7 leftChannel.currentLevel = 7
println(leftChannel.currentLevel) println(leftChannel.currentLevel)
// 输出 "7" // 输出 "7"
println(AudioChannel.maxInputLevelForAllChannels) println(AudioChannel.maxInputLevelForAllChannels)
// 输出 "7" // 输出 "7"
``` ```
如果试图将右声道的电平设置成 11则会将右声道的`currentLevel`修正到最大值 10同时`maxInputLevelForAllChannels`的值也会更新到 10 如果试图将右声道的电平设置成 11则会将右声道的`currentLevel`修正到最大值 10同时`maxInputLevelForAllChannels`的值也会更新到 10
``` ```swift
rightChannel.currentLevel = 11 rightChannel.currentLevel = 11
println(rightChannel.currentLevel) println(rightChannel.currentLevel)
// 输出 "10" // 输出 "10"
println(AudioChannel.maxInputLevelForAllChannels) println(AudioChannel.maxInputLevelForAllChannels)
// 输出 "10" // 输出 "10"
``` ```

View File

@ -1,15 +1,13 @@
> 翻译pp-prog > 翻译pp-prog
> 校对zqp
> 校对zqp
# 方法Methods # 方法Methods
----------------- -----------------
本页包含内容: 本页包含内容:
- [实例方法(Instance Methods](#instance_methods) - [实例方法(Instance Methods](#instance_methods)
- [类型方法(Type Methods)](#type_methods) - [类型方法(Type Methods)](#type_methods)
**方法**是与某些特定类型相关联的函数。类、结构体、枚举都可以定义实例方法;实例方法为给定类型的实例封装了具体的任务与功能。类、结构体、枚举也可以定义类型方法;类型方法与类型本身相关联。类型方法与 Objective-C 中的类方法class methods相似。 **方法**是与某些特定类型相关联的函数。类、结构体、枚举都可以定义实例方法;实例方法为给定类型的实例封装了具体的任务与功能。类、结构体、枚举也可以定义类型方法;类型方法与类型本身相关联。类型方法与 Objective-C 中的类方法class methods相似。
@ -24,7 +22,7 @@
下面的例子,定义一个很简单的类`Counter``Counter`能被用来对一个动作发生的次数进行计数: 下面的例子,定义一个很简单的类`Counter``Counter`能被用来对一个动作发生的次数进行计数:
``` ```swift
class Counter { class Counter {
var count = 0 var count = 0
func increment() { func increment() {
@ -48,7 +46,7 @@ class Counter {
和调用属性一样用点语法dot syntax调用实例方法 和调用属性一样用点语法dot syntax调用实例方法
``` ```swift
let counter = Counter() let counter = Counter()
// 初始计数值是0 // 初始计数值是0
counter.increment() counter.increment()
@ -58,6 +56,7 @@ class Counter {
counter.reset() counter.reset()
// 计数值现在是0 // 计数值现在是0
``` ```
<a name="local_and_external_parameter"></a> <a name="local_and_external_parameter"></a>
### 方法的局部参数名称和外部参数名称(Local and External Parameter Names for Methods) ### 方法的局部参数名称和外部参数名称(Local and External Parameter Names for Methods)
@ -69,7 +68,7 @@ Swift 中的方法和 Objective-C 中的方法极其相似。像在 Objective-C
看看下面这个`Counter`的另一个版本(它定义了一个更复杂的`incrementBy`方法): 看看下面这个`Counter`的另一个版本(它定义了一个更复杂的`incrementBy`方法):
``` ```swift
class Counter { class Counter {
var count: Int = 0 var count: Int = 0
func incrementBy(amount: Int, numberOfTimes: Int) { func incrementBy(amount: Int, numberOfTimes: Int) {
@ -80,7 +79,7 @@ class Counter {
`incrementBy`方法有两个参数: `amount``numberOfTimes`。默认情况下Swift 只把`amount`当作一个局部名称,但是把`numberOfTimes`即看作局部名称又看作外部名称。下面调用这个方法: `incrementBy`方法有两个参数: `amount``numberOfTimes`。默认情况下Swift 只把`amount`当作一个局部名称,但是把`numberOfTimes`即看作局部名称又看作外部名称。下面调用这个方法:
``` ```swift
let counter = Counter() let counter = Counter()
counter.incrementBy(5, numberOfTimes: 3) counter.incrementBy(5, numberOfTimes: 3)
// counter value is now 15 // counter value is now 15
@ -90,9 +89,9 @@ counter.incrementBy(5, numberOfTimes: 3)
这种默认的行为能够有效的处理方法method,类似于在参数`numberOfTimes`前写一个井号(`#` 这种默认的行为能够有效的处理方法method,类似于在参数`numberOfTimes`前写一个井号(`#`
``` ```swift
func incrementBy(amount: Int, #numberOfTimes: Int) { func incrementBy(amount: Int, #numberOfTimes: Int) {
count += amount * numberOfTimes count += amount * numberOfTimes
} }
``` ```
@ -111,7 +110,8 @@ func incrementBy(amount: Int, #numberOfTimes: Int) {
类型的每一个实例都有一个隐含属性叫做`self``self`完全等同于该实例本身。你可以在一个实例的实例方法中使用这个隐含的`self`属性来引用当前实例。 类型的每一个实例都有一个隐含属性叫做`self``self`完全等同于该实例本身。你可以在一个实例的实例方法中使用这个隐含的`self`属性来引用当前实例。
上面例子中的`increment`方法还可以这样写: 上面例子中的`increment`方法还可以这样写:
```
```swift
func increment() { func increment() {
self.count++ self.count++
} }
@ -123,7 +123,7 @@ func increment() {
下面的例子中,`self`消除方法参数`x`和实例属性`x`之间的歧义: 下面的例子中,`self`消除方法参数`x`和实例属性`x`之间的歧义:
``` ```swift
struct Point { struct Point {
var x = 0.0, y = 0.0 var x = 0.0, y = 0.0
func isToTheRightOfX(x: Double) -> Bool { func isToTheRightOfX(x: Double) -> Bool {
@ -148,7 +148,7 @@ if somePoint.isToTheRightOfX(1.0) {
要使用`变异`方法, 将关键字`mutating` 放到方法的`func`关键字之前就可以了: 要使用`变异`方法, 将关键字`mutating` 放到方法的`func`关键字之前就可以了:
``` ```swift
struct Point { struct Point {
var x = 0.0, y = 0.0 var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) { mutating func moveByX(deltaX: Double, y deltaY: Double) {
@ -166,17 +166,18 @@ println("The point is now at (\(somePoint.x), \(somePoint.y))")
注意:不能在结构体类型常量上调用变异方法,因为常量的属性不能被改变,即使想改变的是常量的变量属性也不行,详情参见[存储属性和实例变量]("10_Properties.html") 注意:不能在结构体类型常量上调用变异方法,因为常量的属性不能被改变,即使想改变的是常量的变量属性也不行,详情参见[存储属性和实例变量]("10_Properties.html")
``` ```swift
let fixedPoint = Point(x: 3.0, y: 3.0) let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveByX(2.0, y: 3.0) fixedPoint.moveByX(2.0, y: 3.0)
// this will report an error // this will report an error
``` ```
<a name="mutating_method_self"></a> <a name="mutating_method_self"></a>
### 在变异方法中给self赋值(Assigning to self Within a Mutating Method) ### 在变异方法中给self赋值(Assigning to self Within a Mutating Method)
变异方法能够赋给隐含属性`self`一个全新的实例。上面`Point`的例子可以用下面的方式改写: 变异方法能够赋给隐含属性`self`一个全新的实例。上面`Point`的例子可以用下面的方式改写:
``` ```swift
struct Point { struct Point {
var x = 0.0, y = 0.0 var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) { mutating func moveByX(deltaX: Double, y deltaY: Double) {
@ -189,7 +190,7 @@ struct Point {
枚举的变异方法可以把`self`设置为相同的枚举类型中不同的成员: 枚举的变异方法可以把`self`设置为相同的枚举类型中不同的成员:
``` ```swift
enum TriStateSwitch { enum TriStateSwitch {
case Off, Low, High case Off, Low, High
mutating func next() { mutating func next() {
@ -217,13 +218,12 @@ ovenLight.next()
实例方法是被类型的某个实例调用的方法。你也可以定义类型本身调用的方法,这种方法就叫做**类型方法**。声明类的类型方法,在方法的`func`关键字之前加上关键字`class`;声明结构体和枚举的类型方法,在方法的`func`关键字之前加上关键字`static` 实例方法是被类型的某个实例调用的方法。你也可以定义类型本身调用的方法,这种方法就叫做**类型方法**。声明类的类型方法,在方法的`func`关键字之前加上关键字`class`;声明结构体和枚举的类型方法,在方法的`func`关键字之前加上关键字`static`
> 注意: > 注意:
> 在 Objective-C 里面,你只能为 Objective-C 的类定义类型方法type-level methods。在 Swift 中,你可以为所有的类、结构体和枚举定义类型方法:每一个类型方法都被它所支持的类型显式包含。
> 在 Objective-C 里面,你只能为 Objective-C 的类定义类型方法type-level methods。在 Swift 中,你可以为所有的类、结构体和枚举定义类型方法:每一个类型方法都被它所支持的类型显式包含。
类型方法和实例方法一样用点语法调用。但是,你是在类型层面上调用这个方法,而不是在实例层面上调用。下面是如何在`SomeClass`类上调用类型方法的例子: 类型方法和实例方法一样用点语法调用。但是,你是在类型层面上调用这个方法,而不是在实例层面上调用。下面是如何在`SomeClass`类上调用类型方法的例子:
``` ```swift
class SomeClass { class SomeClass {
class func someTypeMethod() { class func someTypeMethod() {
// type method implementation goes here // type method implementation goes here
@ -240,7 +240,7 @@ SomeClass.someTypeMethod()
游戏初始时,所有的游戏等级(除了等级 1都被锁定。每次有玩家完成一个等级这个等级就对这个设备上的所有玩家解锁。`LevelTracker`结构体用静态属性和方法监测游戏的哪个等级已经被解锁。它还监测每个玩家的当前等级。 游戏初始时,所有的游戏等级(除了等级 1都被锁定。每次有玩家完成一个等级这个等级就对这个设备上的所有玩家解锁。`LevelTracker`结构体用静态属性和方法监测游戏的哪个等级已经被解锁。它还监测每个玩家的当前等级。
``` ```swift
struct LevelTracker { struct LevelTracker {
static var highestUnlockedLevel = 1 static var highestUnlockedLevel = 1
static func unlockLevel(level: Int) { static func unlockLevel(level: Int) {
@ -271,7 +271,7 @@ struct LevelTracker {
下面,`Player`类使用`LevelTracker`来监测和更新每个玩家的发展进度: 下面,`Player`类使用`LevelTracker`来监测和更新每个玩家的发展进度:
``` ```swift
class Player { class Player {
var tracker = LevelTracker() var tracker = LevelTracker()
let playerName: String let playerName: String
@ -289,22 +289,21 @@ class Player {
你还可以为一个新的玩家创建一个`Player`的实例,然后看这个玩家完成等级一时发生了什么: 你还可以为一个新的玩家创建一个`Player`的实例,然后看这个玩家完成等级一时发生了什么:
``` ```swift
var player = Player(name: "Argyrios") var player = Player(name: "Argyrios")
player.completedLevel(1) player.completedLevel(1)
println("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)") println("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// 输出 "highest unlocked level is now 2"最高等级现在是2 // 输出 "highest unlocked level is now 2"最高等级现在是2
``` ```
如果你创建了第二个玩家,并尝试让他开始一个没有被任何玩家解锁的等级,那么这次设置玩家当前等级的尝试将会失败: 如果你创建了第二个玩家,并尝试让他开始一个没有被任何玩家解锁的等级,那么这次设置玩家当前等级的尝试将会失败:
``` ```swift
player = Player(name: "Beto") player = Player(name: "Beto")
if player.tracker.advanceToLevel(6) { if player.tracker.advanceToLevel(6) {
println("player is now on level 6") println("player is now on level 6")
} else { } else {
println("level 6 has not yet been unlocked") println("level 6 has not yet been unlocked")
} }
// 输出 "level 6 has not yet been unlocked"等级6还没被解锁 // 输出 "level 6 has not yet been unlocked"等级6还没被解锁
``` ```

View File

@ -1,6 +1,5 @@
> 翻译siemenliu > 翻译siemenliu
> 校对zq54zquan
> 校对zq54zquan
# 附属脚本Subscripts # 附属脚本Subscripts
@ -16,22 +15,22 @@
对于同一个目标可以定义多个附属脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。 对于同一个目标可以定义多个附属脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。
> 译者:这里附属脚本重载在本小节中原文并没有任何演示 > 译者:这里附属脚本重载在本小节中原文并没有任何演示
<a name="subscript_syntax"></a> <a name="subscript_syntax"></a>
## 附属脚本语法 ## 附属脚本语法
附属脚本允许你通过在实例后面的方括号中传入一个或者多个的索引值来对实例进行访问和赋值。语法类似于实例方法和计算型属性的混合。与定义实例方法类似,定义附属脚本使用`subscript`关键字显式声明入参一个或多个和返回类型。与实例方法不同的是附属脚本可以设定为读写或只读。这种方式又有点像计算型属性的getter和setter 附属脚本允许你通过在实例后面的方括号中传入一个或者多个的索引值来对实例进行访问和赋值。语法类似于实例方法和计算型属性的混合。与定义实例方法类似,定义附属脚本使用`subscript`关键字显式声明入参一个或多个和返回类型。与实例方法不同的是附属脚本可以设定为读写或只读。这种方式又有点像计算型属性的getter和setter
``` ```swift
subscript(index: Int) -> Int { subscript(index: Int) -> Int {
get { get {
// 返回与入参匹配的Int类型的值 // 返回与入参匹配的Int类型的值
} }
set(newValue) { set(newValue) {
// 执行赋值操作 // 执行赋值操作
} }
} }
``` ```
@ -39,20 +38,20 @@ subscript(index: Int) -> Int {
与只读计算型属性一样,可以直接将原本应该写在`get`代码块中的代码写在`subscript`中: 与只读计算型属性一样,可以直接将原本应该写在`get`代码块中的代码写在`subscript`中:
``` ```swift
subscript(index: Int) -> Int { subscript(index: Int) -> Int {
// 返回与入参匹配的Int类型的值 // 返回与入参匹配的Int类型的值
} }
``` ```
下面代码演示了一个在`TimesTable`结构体中使用只读附属脚本的用法,该结构体用来展示传入整数的*n*倍。 下面代码演示了一个在`TimesTable`结构体中使用只读附属脚本的用法,该结构体用来展示传入整数的*n*倍。
``` ```swift
struct TimesTable { struct TimesTable {
let multiplier: Int let multiplier: Int
subscript(index: Int) -> Int { subscript(index: Int) -> Int {
return multiplier * index return multiplier * index
} }
} }
let threeTimesTable = TimesTable(multiplier: 3) let threeTimesTable = TimesTable(multiplier: 3)
println("3的6倍是\(threeTimesTable[6])") println("3的6倍是\(threeTimesTable[6])")
@ -63,9 +62,8 @@ println("3的6倍是\(threeTimesTable[6])")
你可以通过附属脚本来得到结果,比如`threeTimesTable[6]`。这条语句访问了`threeTimesTable`的第六个元素,返回`6``3`倍即`18` 你可以通过附属脚本来得到结果,比如`threeTimesTable[6]`。这条语句访问了`threeTimesTable`的第六个元素,返回`6``3`倍即`18`
>注意: >注意:
> > `TimesTable`例子是基于一个固定的数学公式。它并不适合开放写权限来对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么附属脚本只定义为只读的原因。
> `TimesTable`例子是基于一个固定的数学公式。它并不适合开放写权限来对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么附属脚本只定义为只读的原因。
<a name="subscript_usage"></a> <a name="subscript_usage"></a>
@ -75,7 +73,7 @@ println("3的6倍是\(threeTimesTable[6])")
例如Swift 的字典Dictionary实现了通过附属脚本来对其实例中存放的值进行存取操作。在附属脚本中使用和字典索引相同类型的值并且把一个字典值类型的值赋值给这个附属脚本来为字典设值 例如Swift 的字典Dictionary实现了通过附属脚本来对其实例中存放的值进行存取操作。在附属脚本中使用和字典索引相同类型的值并且把一个字典值类型的值赋值给这个附属脚本来为字典设值
``` ```swift
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2 numberOfLegs["bird"] = 2
``` ```
@ -84,9 +82,8 @@ numberOfLegs["bird"] = 2
更多关于字典Dictionary附属脚本的信息请参考[读取和修改字典](../chapter2/04_Collection_Types.html) 更多关于字典Dictionary附属脚本的信息请参考[读取和修改字典](../chapter2/04_Collection_Types.html)
> 注意: > 注意:
> > Swift 中字典的附属脚本实现中,在`get`部分返回值是`Int?`,上例中的`numberOfLegs`字典通过附属脚本返回的是一个`Int?`或者说“可选的int”不是每个字典的索引都能得到一个整型值对于没有设过值的索引的访问返回的结果就是`nil`;同样想要从字典实例中删除某个索引下的值也只需要给这个索引赋值为`nil`即可。
> Swift 中字典的附属脚本实现中,在`get`部分返回值是`Int?`,上例中的`numberOfLegs`字典通过附属脚本返回的是一个`Int?`或者说“可选的int”不是每个字典的索引都能得到一个整型值对于没有设过值的索引的访问返回的结果就是`nil`;同样想要从字典实例中删除某个索引下的值也只需要给这个索引赋值为`nil`即可。
<a name="subscript_options"></a> <a name="subscript_options"></a>
## 附属脚本选项 ## 附属脚本选项
@ -97,16 +94,16 @@ numberOfLegs["bird"] = 2
一个附属脚本入参是最常见的情况,但只要有合适的场景也可以定义多个附属脚本入参。如下例定义了一个`Matrix`结构体,将呈现一个`Double`类型的二维矩阵。`Matrix`结构体的附属脚本需要两个整型参数: 一个附属脚本入参是最常见的情况,但只要有合适的场景也可以定义多个附属脚本入参。如下例定义了一个`Matrix`结构体,将呈现一个`Double`类型的二维矩阵。`Matrix`结构体的附属脚本需要两个整型参数:
``` ```swift
struct Matrix { struct Matrix {
let rows: Int, columns: Int let rows: Int, columns: Int
var grid: Double[] var grid: Double[]
init(rows: Int, columns: Int) { init(rows: Int, columns: Int) {
self.rows = rows self.rows = rows
self.columns = columns self.columns = columns
grid = Array(count: rows * columns, repeatedValue: 0.0) grid = Array(count: rows * columns, repeatedValue: 0.0)
} }
func indexIsValidForRow(row: Int, column: Int) -> Bool { func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns return row >= 0 && row < rows && column >= 0 && column < columns
} }
subscript(row: Int, column: Int) -> Double { subscript(row: Int, column: Int) -> Double {
@ -118,7 +115,7 @@ struct Matrix {
assert(indexIsValidForRow(row, column: column), "Index out of range") assert(indexIsValidForRow(row, column: column), "Index out of range")
grid[(row * columns) + columns] = newValue grid[(row * columns) + columns] = newValue
} }
} }
} }
``` ```
@ -126,38 +123,38 @@ struct Matrix {
你可以通过传入合适的`row``column`的数量来构造一个新的`Matrix`实例: 你可以通过传入合适的`row``column`的数量来构造一个新的`Matrix`实例:
``` ```swift
var matrix = Matrix(rows: 2, columns: 2) var matrix = Matrix(rows: 2, columns: 2)
``` ```
上例中创建了一个新的两行两列的`Matrix`实例。在阅读顺序从左上到右下的`Matrix`实例中的数组实例`grid`是矩阵二维数组的扁平化存储: 上例中创建了一个新的两行两列的`Matrix`实例。在阅读顺序从左上到右下的`Matrix`实例中的数组实例`grid`是矩阵二维数组的扁平化存储:
``` ```swift
// 示意图 // 示意图
grid = [0.0, 0.0, 0.0, 0.0] grid = [0.0, 0.0, 0.0, 0.0]
col0 col1 col0 col1
row0 [0.0, 0.0, row0 [0.0, 0.0,
row1 0.0, 0.0] row1 0.0, 0.0]
``` ```
将值赋给带有`row``column`附属脚本的`matrix`实例表达式可以完成赋值操作,附属脚本入参使用逗号分割 将值赋给带有`row``column`附属脚本的`matrix`实例表达式可以完成赋值操作,附属脚本入参使用逗号分割
``` ```swift
matrix[0, 1] = 1.5 matrix[0, 1] = 1.5
matrix[1, 0] = 3.2 matrix[1, 0] = 3.2
``` ```
上面两条语句分别`让matrix`的右上值为 1.5,坐下值为 3.2 上面两条语句分别`让matrix`的右上值为 1.5,坐下值为 3.2
``` ```swift
[0.0, 1.5, [0.0, 1.5,
3.2, 0.0] 3.2, 0.0]
``` ```
`Matrix`附属脚本的`getter``setter`中同时调用了附属脚本入参的`row``column`是否有效的判断。为了方便进行断言,`Matrix`包含了一个名为`indexIsValid`的成员方法,用来确认入参的`row``column`值是否会造成数组越界: `Matrix`附属脚本的`getter``setter`中同时调用了附属脚本入参的`row``column`是否有效的判断。为了方便进行断言,`Matrix`包含了一个名为`indexIsValid`的成员方法,用来确认入参的`row``column`值是否会造成数组越界:
``` ```swift
func indexIsValidForRow(row: Int, column: Int) -> Bool { func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns return row >= 0 && row < rows && column >= 0 && column < columns
} }
@ -165,8 +162,7 @@ func indexIsValidForRow(row: Int, column: Int) -> Bool {
断言在附属脚本越界时触发: 断言在附属脚本越界时触发:
``` ```swift
let someValue = matrix[2, 2] let someValue = matrix[2, 2]
// 断言将会触发,因为 [2, 2] 已经超过了matrix的最大长度 // 断言将会触发,因为 [2, 2] 已经超过了matrix的最大长度
``` ```

View File

@ -1,6 +1,5 @@
> 翻译Hawstein > 翻译Hawstein
> 校对menlongsheng
> 校对menlongsheng
# 继承Inheritance # 继承Inheritance
------------------- -------------------
@ -23,13 +22,12 @@
不继承于其它类的类,称之为*基类base calss*。 不继承于其它类的类,称之为*基类base calss*。
> 注意: > 注意:
>
Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。 Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。
下面的例子定义了一个叫`Vehicle`的基类。这个基类声明了两个对所有车辆都通用的属性(`numberOfWheels``maxPassengers`)。这些属性在`description`方法中使用,这个方法返回一个`String`类型的,对车辆特征的描述: 下面的例子定义了一个叫`Vehicle`的基类。这个基类声明了两个对所有车辆都通用的属性(`numberOfWheels``maxPassengers`)。这些属性在`description`方法中使用,这个方法返回一个`String`类型的,对车辆特征的描述:
``` ```swift
class Vehicle { class Vehicle {
var numberOfWheels: Int var numberOfWheels: Int
var maxPassengers: Int var maxPassengers: Int
@ -49,7 +47,7 @@ class Vehicle {
构造器的最简单形式就像一个没有参数的实例方法,使用`init`关键字: 构造器的最简单形式就像一个没有参数的实例方法,使用`init`关键字:
``` ```swift
init() { init() {
// 执行构造过程 // 执行构造过程
} }
@ -57,7 +55,7 @@ init() {
如果要创建一个`Vehicle`类的新实例,使用*构造器*语法调用上面的初始化器,即类名后面跟一个空的小括号: 如果要创建一个`Vehicle`类的新实例,使用*构造器*语法调用上面的初始化器,即类名后面跟一个空的小括号:
``` ```swift
let someVehicle = Vehicle() let someVehicle = Vehicle()
``` ```
@ -72,18 +70,19 @@ let someVehicle = Vehicle()
为了指明某个类的超类,将超类名写在子类名的后面,用冒号分隔: 为了指明某个类的超类,将超类名写在子类名的后面,用冒号分隔:
``` ```swift
class SomeClass: SomeSuperclass { class SomeClass: SomeSuperclass {
// 类的定义 // 类的定义
} }
``` ```
下一个例子,定义一个更具体的车辆类叫`Bicycle`。这个新类是在 `Vehicle`类的基础上创建起来。因此你需要将`Vehicle`类放在 `Bicycle`类后面,用冒号分隔。 下一个例子,定义一个更具体的车辆类叫`Bicycle`。这个新类是在 `Vehicle`类的基础上创建起来。因此你需要将`Vehicle`类放在 `Bicycle`类后面,用冒号分隔。
我们可以将这读作: 我们可以将这读作:
“定义一个新的类叫`Bicycle `,它继承了`Vehicle`的特性”; “定义一个新的类叫`Bicycle `,它继承了`Vehicle`的特性”;
``` ```swift
class Bicycle: Vehicle { class Bicycle: Vehicle {
init() { init() {
super.init() super.init()
@ -91,19 +90,19 @@ class Bicycle: Vehicle {
} }
} }
``` ```
preview
`Bicycle``Vehicle`的子类,`Vehicle``Bicycle`的超类。新的`Bicycle`类自动获得`Vehicle`类的特性,比如 `maxPassengers``numberOfWheels`属性。你可以在子类中定制这些特性,或添加新的特性来更好地描述`Bicycle`类。 `Bicycle``Vehicle`的子类,`Vehicle``Bicycle`的超类。新的`Bicycle`类自动获得`Vehicle`类的特性,比如 `maxPassengers``numberOfWheels`属性。你可以在子类中定制这些特性,或添加新的特性来更好地描述`Bicycle`类。
`Bicycle`类定义了一个构造器来设置它定制的特性自行车只有2个轮子`Bicycle`的构造器调用了它父类`Vehicle`的构造器 `super.init()`,以此确保在`Bicycle`类试图修改那些继承来的属性前`Vehicle`类已经初始化过它们了。 `Bicycle`类定义了一个构造器来设置它定制的特性自行车只有2个轮子`Bicycle`的构造器调用了它父类`Vehicle`的构造器 `super.init()`,以此确保在`Bicycle`类试图修改那些继承来的属性前`Vehicle`类已经初始化过它们了。
> 注意: > 注意:
>
不像 Objective-C在 Swift 中,初始化器默认是不继承的,见[初始化器的继承与重写](../chapter2/_14Initialization.html#initializer_inheritance_and_ overriding) 不像 Objective-C在 Swift 中,初始化器默认是不继承的,见[初始化器的继承与重写](../chapter2/_14Initialization.html#initializer_inheritance_and_ overriding)
`Vehicle`类中`maxPassengers`的默认值对自行车来说已经是正确的,因此在`Bicycle`的构造器中并没有改变它。而`numberOfWheels`原来的值对自行车来说是不正确的,因此在初始化器中将它更改为 2。 `Vehicle`类中`maxPassengers`的默认值对自行车来说已经是正确的,因此在`Bicycle`的构造器中并没有改变它。而`numberOfWheels`原来的值对自行车来说是不正确的,因此在初始化器中将它更改为 2。
`Bicycle`不仅可以继承`Vehicle`的属性,还可以继承它的方法。如果你创建了一个`Bicycle`类的实例,你就可以调用它继承来的`description`方法,并且可以看到,它输出的属性值已经发生了变化: `Bicycle`不仅可以继承`Vehicle`的属性,还可以继承它的方法。如果你创建了一个`Bicycle`类的实例,你就可以调用它继承来的`description`方法,并且可以看到,它输出的属性值已经发生了变化:
``` ```swift
let bicycle = Bicycle() let bicycle = Bicycle()
println("Bicycle: \(bicycle.description())") println("Bicycle: \(bicycle.description())")
// Bicycle: 2 wheels; up to 1 passengers // Bicycle: 2 wheels; up to 1 passengers
@ -111,7 +110,7 @@ println("Bicycle: \(bicycle.description())")
子类还可以继续被其它类继承: 子类还可以继续被其它类继承:
``` ```swift
class Tandem: Bicycle { class Tandem: Bicycle {
init() { init() {
super.init() super.init()
@ -122,13 +121,12 @@ class Tandem: Bicycle {
上面的例子创建了`Bicycle`的一个子类双人自行车tandem`Tandem``Bicycle`继承了两个属性,而这两个属性是`Bicycle``Vehicle`继承而来的。`Tandem`并不修改轮子的数量,因为它仍是一辆自行车,有 2 个轮子。但它需要修改`maxPassengers`的值,因为双人自行车可以坐两个人。 上面的例子创建了`Bicycle`的一个子类双人自行车tandem`Tandem``Bicycle`继承了两个属性,而这两个属性是`Bicycle``Vehicle`继承而来的。`Tandem`并不修改轮子的数量,因为它仍是一辆自行车,有 2 个轮子。但它需要修改`maxPassengers`的值,因为双人自行车可以坐两个人。
> 注意: > 注意:
>
子类只允许修改从超类继承来的变量属性,而不能修改继承来的常量属性。 子类只允许修改从超类继承来的变量属性,而不能修改继承来的常量属性。
创建一个`Tandem`类的实例,打印它的描述,即可看到它的属性已被更新: 创建一个`Tandem`类的实例,打印它的描述,即可看到它的属性已被更新:
``` ```swift
let tandem = Tandem() let tandem = Tandem()
println("Tandem: \(tandem.description())") println("Tandem: \(tandem.description())")
// Tandem: 2 wheels; up to 2 passengers // Tandem: 2 wheels; up to 2 passengers
@ -161,7 +159,7 @@ println("Tandem: \(tandem.description())")
下面的例子定义了`Vehicle`的一个新的子类,叫`Car`,它重写了从`Vehicle`类继承来的`description`方法: 下面的例子定义了`Vehicle`的一个新的子类,叫`Car`,它重写了从`Vehicle`类继承来的`description`方法:
``` ```swift
class Car: Vehicle { class Car: Vehicle {
var speed: Double = 0.0 var speed: Double = 0.0
init() { init() {
@ -184,7 +182,7 @@ class Car: Vehicle {
如果你创建一个`Car`的新实例,并打印`description`方法的输出,你就会发现描述信息已经发生了改变: 如果你创建一个`Car`的新实例,并打印`description`方法的输出,你就会发现描述信息已经发生了改变:
``` ```swift
let car = Car() let car = Car()
println("Car: \(car.description())") println("Car: \(car.description())")
// Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph // Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph
@ -200,13 +198,12 @@ println("Car: \(car.description())")
你可以将一个继承来的只读属性重写为一个读写属性,只需要你在重写版本的属性里提供 getter 和 setter 即可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。 你可以将一个继承来的只读属性重写为一个读写属性,只需要你在重写版本的属性里提供 getter 和 setter 即可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。
> 注意: > 注意:
>
如果你在重写属性中提供了 setter那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接返回`super.someProperty`来返回继承来的值。正如下面的`SpeedLimitedCar`的例子所示。 如果你在重写属性中提供了 setter那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接返回`super.someProperty`来返回继承来的值。正如下面的`SpeedLimitedCar`的例子所示。
以下的例子定义了一个新类,叫`SpeedLimitedCar`,它是`Car`的子类。类`SpeedLimitedCar`表示安装了限速装置的车它的最高速度只能达到40mph。你可以通过重写继承来的`speed`属性来实现这个速度限制: 以下的例子定义了一个新类,叫`SpeedLimitedCar`,它是`Car`的子类。类`SpeedLimitedCar`表示安装了限速装置的车它的最高速度只能达到40mph。你可以通过重写继承来的`speed`属性来实现这个速度限制:
``` ```swift
class SpeedLimitedCar: Car { class SpeedLimitedCar: Car {
override var speed: Double { override var speed: Double {
get { get {
@ -223,7 +220,7 @@ class SpeedLimitedCar: Car {
如果你尝试将`SpeedLimitedCar`实例的`speed`属性设置为一个大于40mph的数然后打印`description`函数的输出你会发现速度被限制在40mph 如果你尝试将`SpeedLimitedCar`实例的`speed`属性设置为一个大于40mph的数然后打印`description`函数的输出你会发现速度被限制在40mph
``` ```swift
let limitedCar = SpeedLimitedCar() let limitedCar = SpeedLimitedCar()
limitedCar.speed = 60.0 limitedCar.speed = 60.0
println("SpeedLimitedCar: \(limitedCar.description())") println("SpeedLimitedCar: \(limitedCar.description())")
@ -234,13 +231,12 @@ println("SpeedLimitedCar: \(limitedCar.description())")
你可以在属性重写中为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会被通知到,无论那个属性原本是如何实现的。关于属性观察器的更多内容,请看[属性观察器](../chapter2/_10Properties.html#property_observer)。 你可以在属性重写中为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会被通知到,无论那个属性原本是如何实现的。关于属性观察器的更多内容,请看[属性观察器](../chapter2/_10Properties.html#property_observer)。
> 注意: > 注意:
>
你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值是不可以被设置的,所以,为它们提供`willSet``didSet`实现是不恰当。此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已经为那个属性提供了定制的 setter那么你在 setter 中就可以观察到任何值变化了。 你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值是不可以被设置的,所以,为它们提供`willSet``didSet`实现是不恰当。此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已经为那个属性提供了定制的 setter那么你在 setter 中就可以观察到任何值变化了。
下面的例子定义了一个新类叫`AutomaticCar`,它是`Car`的子类。`AutomaticCar`表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位。`AutomaticCar`也提供了定制的`description`方法,可以输出当前挡位。 下面的例子定义了一个新类叫`AutomaticCar`,它是`Car`的子类。`AutomaticCar`表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位。`AutomaticCar`也提供了定制的`description`方法,可以输出当前挡位。
``` ```swift
class AutomaticCar: Car { class AutomaticCar: Car {
var gear = 1 var gear = 1
override var speed: Double { override var speed: Double {
@ -256,7 +252,7 @@ class AutomaticCar: Car {
当你设置`AutomaticCar``speed`属性,属性的`didSet`观察器就会自动地设置`gear`属性为新的速度选择一个合适的挡位。具体来说就是属性观察器将新的速度值除以10然后向下取得最接近的整数值最后加1来得到档位`gear`的值。例如速度为10.0时挡位为1速度为35.0时挡位为4 当你设置`AutomaticCar``speed`属性,属性的`didSet`观察器就会自动地设置`gear`属性为新的速度选择一个合适的挡位。具体来说就是属性观察器将新的速度值除以10然后向下取得最接近的整数值最后加1来得到档位`gear`的值。例如速度为10.0时挡位为1速度为35.0时挡位为4
``` ```swift
let automatic = AutomaticCar() let automatic = AutomaticCar()
automatic.speed = 35.0 automatic.speed = 35.0
println("AutomaticCar: \(automatic.description())") println("AutomaticCar: \(automatic.description())")
@ -271,3 +267,4 @@ println("AutomaticCar: \(automatic.description())")
如果你重写了`final`方法,属性或附属脚本,在编译时会报错。在扩展中,你添加到类里的方法,属性或附属脚本也可以在扩展的定义里标记为 final。 如果你重写了`final`方法,属性或附属脚本,在编译时会报错。在扩展中,你添加到类里的方法,属性或附属脚本也可以在扩展的定义里标记为 final。
你可以通过在关键字`class`前添加`@final`特性(`@final class`)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。 你可以通过在关键字`class`前添加`@final`特性(`@final class`)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。

View File

@ -1,6 +1,5 @@
> 翻译lifedim > 翻译lifedim
> 校对lifedim
> 校对lifedim
# 构造过程Initialization # 构造过程Initialization
@ -29,8 +28,7 @@
你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值。以下章节将详细介绍这两种方法。 你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值。以下章节将详细介绍这两种方法。
>注意: >注意:
>
当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观测器(`property observers`)。 当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观测器(`property observers`)。
### 构造器 ### 构造器
@ -39,16 +37,20 @@
下面例子中定义了一个用来保存华氏温度的结构体`Fahrenheit`,它拥有一个`Double`类型的存储型属性`temperature` 下面例子中定义了一个用来保存华氏温度的结构体`Fahrenheit`,它拥有一个`Double`类型的存储型属性`temperature`
struct Fahrenheit { ```swift
var temperature: Double struct Fahrenheit {
init() { var temperature: Double
temperature = 32.0 init() {
} temperature = 32.0
} }
}
```
var f = Fahrenheit() ```swift
println("The default temperature is \(f.temperature)° Fahrenheit") var f = Fahrenheit()
// 输出 "The default temperature is 32.0° Fahrenheit println("The default temperature is \(f.temperature)° Fahrenheit")
// 输出 "The default temperature is 32.0° Fahrenheit”
```
这个结构体定义了一个不带参数的构造器`init`,并在里面将存储型属性`temperature`的值初始化为`32.0`(华摄氏度下水的冰点)。 这个结构体定义了一个不带参数的构造器`init`,并在里面将存储型属性`temperature`的值初始化为`32.0`(华摄氏度下水的冰点)。
@ -56,15 +58,16 @@
如前所述,你可以在构造器中为存储型属性设置初始值;同样,你也可以在属性声明时为其设置默认值。 如前所述,你可以在构造器中为存储型属性设置初始值;同样,你也可以在属性声明时为其设置默认值。
>注意: >注意:
>
如果一个属性总是使用同一个初始值,可以为其设置一个默认值。无论定义默认值还是在构造器中赋值,最终它们实现的效果是一样的,只不过默认值跟属性构造过程结合的更紧密。使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型;同时,它也能让你充分利用默认构造器、构造器继承(后续章节将讲到)等特性。 如果一个属性总是使用同一个初始值,可以为其设置一个默认值。无论定义默认值还是在构造器中赋值,最终它们实现的效果是一样的,只不过默认值跟属性构造过程结合的更紧密。使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型;同时,它也能让你充分利用默认构造器、构造器继承(后续章节将讲到)等特性。
你可以使用更简单的方式在定义结构体`Fahrenheit`时为属性`temperature`设置默认值: 你可以使用更简单的方式在定义结构体`Fahrenheit`时为属性`temperature`设置默认值:
struct Fahrenheit { ```swift
var temperature = 32.0 struct Fahrenheit {
} var temperature = 32.0
}
```
<a name="customizing_initialization"></a> <a name="customizing_initialization"></a>
## 定制化构造过程 ## 定制化构造过程
@ -77,20 +80,24 @@
下面例子中定义了一个包含摄氏度温度的结构体`Celsius`。它定义了两个不同的构造器:`init(fromFahrenheit:)``init(fromKelvin:)`,二者分别通过接受不同刻度表示的温度值来创建新的实例: 下面例子中定义了一个包含摄氏度温度的结构体`Celsius`。它定义了两个不同的构造器:`init(fromFahrenheit:)``init(fromKelvin:)`,二者分别通过接受不同刻度表示的温度值来创建新的实例:
struct Celsius { ```swift
var temperatureInCelsius: Double = 0.0 struct Celsius {
init(fromFahrenheit fahrenheit: Double) { var temperatureInCelsius: Double = 0.0
temperatureInCelsius = (fahrenheit - 32.0) / 1.8 init(fromFahrenheit fahrenheit: Double) {
} temperatureInCelsius = (fahrenheit - 32.0) / 1.8
init(fromKelvin kelvin: Double) { }
temperatureInCelsius = kelvin - 273.15 init(fromKelvin kelvin: Double) {
} temperatureInCelsius = kelvin - 273.15
} }
}
```
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0) ```swift
// boilingPointOfWater.temperatureInCelsius 是 100.0 let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
let freezingPointOfWater = Celsius(fromKelvin: 273.15) // boilingPointOfWater.temperatureInCelsius 是 100.0
// freezingPointOfWater.temperatureInCelsius 是 0.0” let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius 是 0.0”
```
第一个构造器拥有一个构造参数,其外部名字为`fromFahrenheit`,内部名字为`fahrenheit`;第二个构造器也拥有一个构造参数,其外部名字为`fromKelvin`,内部名字为`kelvin`。这两个构造器都将唯一的参数值转换成摄氏温度值,并保存在属性`temperatureInCelsius`中。 第一个构造器拥有一个构造参数,其外部名字为`fromFahrenheit`,内部名字为`fahrenheit`;第二个构造器也拥有一个构造参数,其外部名字为`fromKelvin`,内部名字为`kelvin`。这两个构造器都将唯一的参数值转换成摄氏温度值,并保存在属性`temperatureInCelsius`中。
@ -100,31 +107,36 @@
然而构造器并不像函数和方法那样在括号前有一个可辨别的名字。所以在调用构造器时主要通过构造器中的参数名和类型来确定需要调用的构造器。正因为参数如此重要如果你在定义构造器时没有提供参数的外部名字Swift 会为每个构造器的参数自动生成一个跟内部名字相同的外部名,就相当于在每个构造参数之前加了一个哈希符号。 然而构造器并不像函数和方法那样在括号前有一个可辨别的名字。所以在调用构造器时主要通过构造器中的参数名和类型来确定需要调用的构造器。正因为参数如此重要如果你在定义构造器时没有提供参数的外部名字Swift 会为每个构造器的参数自动生成一个跟内部名字相同的外部名,就相当于在每个构造参数之前加了一个哈希符号。
> 注意: > 注意:
>
如果你不希望为构造器的某个参数提供外部名字,你可以使用下划线`_`来显示描述它的外部名,以此覆盖上面所说的默认行为。 如果你不希望为构造器的某个参数提供外部名字,你可以使用下划线`_`来显示描述它的外部名,以此覆盖上面所说的默认行为。
以下例子中定义了一个结构体`Color`,它包含了三个常量:`red``green``blue`。这些属性可以存储0.0到1.0之间的值,用来指示颜色中红、绿、蓝成分的含量。 以下例子中定义了一个结构体`Color`,它包含了三个常量:`red``green``blue`。这些属性可以存储0.0到1.0之间的值,用来指示颜色中红、绿、蓝成分的含量。
`Color`提供了一个构造器,其中包含三个`Double`类型的构造参数: `Color`提供了一个构造器,其中包含三个`Double`类型的构造参数:
struct Color { ```swift
let red = 0.0, green = 0.0, blue = 0.0 struct Color {
init(red: Double, green: Double, blue: Double) { let red = 0.0, green = 0.0, blue = 0.0
self.red = red init(red: Double, green: Double, blue: Double) {
self.green = green self.red = red
self.blue = blue self.green = green
} self.blue = blue
} }
}
```
每当你创建一个新的`Color`实例,你都需要通过三种颜色的外部参数名来传值,并调用构造器。 每当你创建一个新的`Color`实例,你都需要通过三种颜色的外部参数名来传值,并调用构造器。
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0) ```swift
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
```
注意,如果不通过外部参数名字传值,你是没法调用这个构造器的。只要构造器定义了某个外部参数名,你就必须使用它,忽略它将导致编译错误: 注意,如果不通过外部参数名字传值,你是没法调用这个构造器的。只要构造器定义了某个外部参数名,你就必须使用它,忽略它将导致编译错误:
let veryGreen = Color(0.0, 1.0, 0.0) ```swift
// 报编译时错误,需要外部名称 let veryGreen = Color(0.0, 1.0, 0.0)
// 报编译时错误,需要外部名称
```
### 可选属性类型 ### 可选属性类型
@ -132,20 +144,22 @@
下面例子中定义了类`SurveyQuestion`,它包含一个可选字符串属性`response` 下面例子中定义了类`SurveyQuestion`,它包含一个可选字符串属性`response`
class SurveyQuestion { ```swift
var text: String class SurveyQuestion {
var response: String? var text: String
init(text: String) { var response: String?
self.text = text init(text: String) {
} self.text = text
func ask() { }
println(text) func ask() {
} println(text)
} }
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?") }
cheeseQuestion.ask() let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
// 输出 "Do you like cheese?" cheeseQuestion.ask()
cheeseQuestion.response = "Yes, I do like cheese. // 输出 "Do you like cheese?"
cheeseQuestion.response = "Yes, I do like cheese.
```
调查问题在问题提出之后,我们才能得到回答。所以我们将属性回答`response`声明为`String?`类型,或者说是可选字符串类型`optional String`。当`SurveyQuestion`实例化时,它将自动赋值为空`nil`,表明暂时还不存在此字符串。 调查问题在问题提出之后,我们才能得到回答。所以我们将属性回答`response`声明为`String?`类型,或者说是可选字符串类型`optional String`。当`SurveyQuestion`实例化时,它将自动赋值为空`nil`,表明暂时还不存在此字符串。
@ -153,26 +167,27 @@
只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值。 只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值。
>注意: >注意:
>
对某个类实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。 对某个类实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。
你可以修改上面的`SurveyQuestion`示例,用常量属性替代变量属性`text`,指明问题内容`text`在其创建之后不会再被修改。尽管`text`属性现在是常量,我们仍然可以在其类的构造器中修改它的值: 你可以修改上面的`SurveyQuestion`示例,用常量属性替代变量属性`text`,指明问题内容`text`在其创建之后不会再被修改。尽管`text`属性现在是常量,我们仍然可以在其类的构造器中修改它的值:
class SurveyQuestion { ```swift
let text: String class SurveyQuestion {
var response: String? let text: String
init(text: String) { var response: String?
self.text = text init(text: String) {
} self.text = text
func ask() { }
println(text) func ask() {
} println(text)
} }
let beetsQuestion = SurveyQuestion(text: "How about beets?") }
beetsQuestion.ask() let beetsQuestion = SurveyQuestion(text: "How about beets?")
// 输出 "How about beets?" beetsQuestion.ask()
beetsQuestion.response = "I also like beets. (But not with cheese.) // 输出 "How about beets?"
beetsQuestion.response = "I also like beets. (But not with cheese.)
```
<a name="default_initializers"></a> <a name="default_initializers"></a>
## 默认构造器 ## 默认构造器
@ -181,12 +196,14 @@ Swift 将为所有属性已提供默认值的且自身没有定义任何构造
下面例子中创建了一个类`ShoppingListItem`,它封装了购物清单中的某一项的属性:名字(`name`)、数量(`quantity`)和购买状态 `purchase state` 下面例子中创建了一个类`ShoppingListItem`,它封装了购物清单中的某一项的属性:名字(`name`)、数量(`quantity`)和购买状态 `purchase state`
class ShoppingListItem { ```swift
var name: String? class ShoppingListItem {
var quantity = 1 var name: String?
var purchased = false var quantity = 1
} var purchased = false
var item = ShoppingListItem() }
var item = ShoppingListItem()
```
由于`ShoppingListItem`类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个可以为所有属性设置默认值的默认构造器(尽管代码中没有显式为`name`属性设置默认值,但由于`name`是可选字符串类型,它将默认设置为`nil`)。上面例子中使用默认构造器创造了一个`ShoppingListItem`类的实例(使用`ShoppingListItem()`形式的构造器语法),并将其赋值给变量`item` 由于`ShoppingListItem`类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个可以为所有属性设置默认值的默认构造器(尽管代码中没有显式为`name`属性设置默认值,但由于`name`是可选字符串类型,它将默认设置为`nil`)。上面例子中使用默认构造器创造了一个`ShoppingListItem`类的实例(使用`ShoppingListItem()`形式的构造器语法),并将其赋值给变量`item`
@ -200,10 +217,12 @@ Swift 将为所有属性已提供默认值的且自身没有定义任何构造
由于这两个存储型属性都有默认值,结构体`Size`自动获得了一个逐一成员构造器 `init(width:height:)`。 你可以用它来为`Size`创建新的实例: 由于这两个存储型属性都有默认值,结构体`Size`自动获得了一个逐一成员构造器 `init(width:height:)`。 你可以用它来为`Size`创建新的实例:
struct Size { ```swift
var width = 0.0, height = 0.0 struct Size {
} var width = 0.0, height = 0.0
let twoByTwo = Size(width: 2.0, height: 2.0) }
let twoByTwo = Size(width: 2.0, height: 2.0)
```
<a name="initializer_delegation_for_value_types"></a> <a name="initializer_delegation_for_value_types"></a>
## 值类型的构造器代理 ## 值类型的构造器代理
@ -216,57 +235,65 @@ Swift 将为所有属性已提供默认值的且自身没有定义任何构造
注意,如果你为某个值类型定义了一个定制的构造器,你将无法访问到默认构造器(如果是结构体,则无法访问逐一对象构造器)。这个限制可以防止你在为值类型定义了一个更复杂的,完成了重要准备构造器之后,别人还是错误的使用了那个自动生成的构造器。 注意,如果你为某个值类型定义了一个定制的构造器,你将无法访问到默认构造器(如果是结构体,则无法访问逐一对象构造器)。这个限制可以防止你在为值类型定义了一个更复杂的,完成了重要准备构造器之后,别人还是错误的使用了那个自动生成的构造器。
>注意: >注意:
>
假如你想通过默认构造器、逐一对象构造器以及你自己定制的构造器为值类型创建实例,我们建议你将自己定制的构造器写到扩展(`extension`)中,而不是跟值类型定义混在一起。想查看更多内容,请查看[扩展](../chapter2/20_Extensions.html)章节。 假如你想通过默认构造器、逐一对象构造器以及你自己定制的构造器为值类型创建实例,我们建议你将自己定制的构造器写到扩展(`extension`)中,而不是跟值类型定义混在一起。想查看更多内容,请查看[扩展](../chapter2/20_Extensions.html)章节。
下面例子将定义一个结构体`Rect`,用来展现几何矩形。这个例子需要两个辅助的结构体`Size``Point`,它们各自为其所有的属性提供了初始值`0.0` 下面例子将定义一个结构体`Rect`,用来展现几何矩形。这个例子需要两个辅助的结构体`Size``Point`,它们各自为其所有的属性提供了初始值`0.0`
struct Size { ```swift
var width = 0.0, height = 0.0 struct Size {
} var width = 0.0, height = 0.0
struct Point { }
var x = 0.0, y = 0.0 struct Point {
} var x = 0.0, y = 0.0
}
```
你可以通过以下三种方式为`Rect`创建实例--使用默认的0值来初始化`origin``size`属性;使用特定的`origin``size`实例来初始化;使用特定的`center``size`来初始化。在下面`Rect`结构体定义中,我们为着三种方式提供了三个自定义的构造器: 你可以通过以下三种方式为`Rect`创建实例--使用默认的0值来初始化`origin``size`属性;使用特定的`origin``size`实例来初始化;使用特定的`center``size`来初始化。在下面`Rect`结构体定义中,我们为着三种方式提供了三个自定义的构造器:
struct Rect { ```swift
var origin = Point() struct Rect {
var size = Size() var origin = Point()
init() {} var size = Size()
init(origin: Point, size: Size) { init() {}
self.origin = origin init(origin: Point, size: Size) {
self.size = size self.origin = origin
} self.size = size
init(center: Point, size: Size) { }
let originX = center.x - (size.width / 2) init(center: Point, size: Size) {
let originY = center.y - (size.height / 2) let originX = center.x - (size.width / 2)
self.init(origin: Point(x: originX, y: originY), size: size) let originY = center.y - (size.height / 2)
} self.init(origin: Point(x: originX, y: originY), size: size)
} }
}
```
第一个`Rect`构造器`init()`,在功能上跟没有自定义构造器时自动获得的默认构造器是一样的。这个构造器是一个空函数,使用一对大括号`{}`来描述,它没有执行任何定制的构造过程。调用这个构造器将返回一个`Rect`实例,它的`origin``size`属性都使用定义时的默认值`Point(x: 0.0, y: 0.0)``Size(width: 0.0, height: 0.0)` 第一个`Rect`构造器`init()`,在功能上跟没有自定义构造器时自动获得的默认构造器是一样的。这个构造器是一个空函数,使用一对大括号`{}`来描述,它没有执行任何定制的构造过程。调用这个构造器将返回一个`Rect`实例,它的`origin``size`属性都使用定义时的默认值`Point(x: 0.0, y: 0.0)``Size(width: 0.0, height: 0.0)`
let basicRect = Rect() ```swift
// basicRect 的原点是 (0.0, 0.0),尺寸是 (0.0, 0.0) let basicRect = Rect()
// basicRect 的原点是 (0.0, 0.0),尺寸是 (0.0, 0.0)
```
第二个`Rect`构造器`init(origin:size:)`,在功能上跟结构体在没有自定义构造器时获得的逐一成员构造器是一样的。这个构造器只是简单的将`origin``size`的参数值赋给对应的存储型属性: 第二个`Rect`构造器`init(origin:size:)`,在功能上跟结构体在没有自定义构造器时获得的逐一成员构造器是一样的。这个构造器只是简单的将`origin``size`的参数值赋给对应的存储型属性:
let originRect = Rect(origin: Point(x: 2.0, y: 2.0), ```swift
size: Size(width: 5.0, height: 5.0)) let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
// originRect 的原点是 (2.0, 2.0),尺寸是 (5.0, 5.0) size: Size(width: 5.0, height: 5.0))
// originRect 的原点是 (2.0, 2.0),尺寸是 (5.0, 5.0)
```
第三个`Rect`构造器`init(center:size:)`稍微复杂一点。它先通过`center``size`的值计算出`origin`的坐标。然后再调用(或代理给)`init(origin:size:)`构造器来将新的`origin``size`值赋值到对应的属性中: 第三个`Rect`构造器`init(center:size:)`稍微复杂一点。它先通过`center``size`的值计算出`origin`的坐标。然后再调用(或代理给)`init(origin:size:)`构造器来将新的`origin``size`值赋值到对应的属性中:
let centerRect = Rect(center: Point(x: 4.0, y: 4.0), let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0)) ```swift
size: Size(width: 3.0, height: 3.0))
```
// centerRect 的原点是 (2.5, 2.5),尺寸是 (3.0, 3.0) // centerRect 的原点是 (2.5, 2.5),尺寸是 (3.0, 3.0)
构造器`init(center:size:)`可以自己将`origin``size`的新值赋值到对应的属性中。然而尽量利用现有的构造器和它所提供的功能来实现`init(center:size:)`的功能,是更方便、更清晰和更直观的方法。 构造器`init(center:size:)`可以自己将`origin``size`的新值赋值到对应的属性中。然而尽量利用现有的构造器和它所提供的功能来实现`init(center:size:)`的功能,是更方便、更清晰和更直观的方法。
>注意: >注意:
>
如果你想用另外一种不需要自己定义`init()``init(origin:size:)`的方式来实现这个例子,请参考[扩展](../chapter2/20_Extensions.html)。 如果你想用另外一种不需要自己定义`init()``init(origin:size:)`的方式来实现这个例子,请参考[扩展](../chapter2/20_Extensions.html)。
<a name="class_inheritance_and_initialization"></a> <a name="class_inheritance_and_initialization"></a>
@ -313,8 +340,7 @@ Swift 提供了两种类型的类构造器来确保所有类实例中存储型
子类中包含两个指定构造器和一个便利构造器。便利构造器必须调用两个指定构造器中的任意一个因为它只能调用同一个类里的其他构造器。这满足了上面提到的规则2和3。而两个指定构造器必须调用父类中唯一的指定构造器这满足了规则1。 子类中包含两个指定构造器和一个便利构造器。便利构造器必须调用两个指定构造器中的任意一个因为它只能调用同一个类里的其他构造器。这满足了上面提到的规则2和3。而两个指定构造器必须调用父类中唯一的指定构造器这满足了规则1。
> 注意: > 注意:
>
这些规则不会影响使用时,如何用类去创建实例。任何上图中展示的构造器都可以用来完整创建对应类的实例。这些规则只在实现类的定义时有影响。 这些规则不会影响使用时,如何用类去创建实例。任何上图中展示的构造器都可以用来完整创建对应类的实例。这些规则只在实现类的定义时有影响。
下面图例中展示了一种更复杂的类层级结构。它演示了指定构造器是如果在类层级中充当“管道”的作用,在类的构造器链上简化了类之间的内部关系。 下面图例中展示了一种更复杂的类层级结构。它演示了指定构造器是如果在类层级中充当“管道”的作用,在类的构造器链上简化了类之间的内部关系。
@ -328,8 +354,7 @@ Swift 中类的构造过程包含两个阶段。第一个阶段,每个存储
两段式构造过程的使用让构造过程更安全,同时在整个类层级结构中给予了每个类完全的灵活性。两段式构造过程可以防止属性值在初始化之前被访问;也可以防止属性被另外一个构造器意外地赋予不同的值。 两段式构造过程的使用让构造过程更安全,同时在整个类层级结构中给予了每个类完全的灵活性。两段式构造过程可以防止属性值在初始化之前被访问;也可以防止属性被另外一个构造器意外地赋予不同的值。
> 注意: > 注意:
>
Swift的两段式构造过程跟 Objective-C 中的构造过程类似。最主要的区别在于阶段 1Objective-C 给每一个属性赋值`0`或空值(比如说`0``nil`。Swift 的构造流程则更加灵活,它允许你设置定制的初始值,并自如应对某些属性不能以`0``nil`作为合法默认值的情况。 Swift的两段式构造过程跟 Objective-C 中的构造过程类似。最主要的区别在于阶段 1Objective-C 给每一个属性赋值`0`或空值(比如说`0``nil`。Swift 的构造流程则更加灵活,它允许你设置定制的初始值,并自如应对某些属性不能以`0``nil`作为合法默认值的情况。
Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造过程能顺利完成: Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造过程能顺利完成:
@ -400,8 +425,7 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
如果你重载的构造器是一个便利构造器,你的重载过程必须通过调用同一类中提供的其它指定构造器来实现。这一规则的详细内容请参考[构造器链](#initialization_chain)。 如果你重载的构造器是一个便利构造器,你的重载过程必须通过调用同一类中提供的其它指定构造器来实现。这一规则的详细内容请参考[构造器链](#initialization_chain)。
>注意: >注意:
>
与方法、属性和下标不同,在重载构造器时你没有必要使用关键字`override` 与方法、属性和下标不同,在重载构造器时你没有必要使用关键字`override`
<a name="automatic_initializer_inheritance"></a> <a name="automatic_initializer_inheritance"></a>
@ -421,23 +445,26 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
即使你在子类中添加了更多的便利构造器,这两条规则仍然适用。 即使你在子类中添加了更多的便利构造器,这两条规则仍然适用。
>注意: >注意:
>
子类可以通过部分满足规则2的方式使用子类便利构造器来实现父类的指定构造器。 子类可以通过部分满足规则2的方式使用子类便利构造器来实现父类的指定构造器。
### 指定构造器和便利构造器的语法 ### 指定构造器和便利构造器的语法
类的指定构造器的写法跟值类型简单构造器一样: 类的指定构造器的写法跟值类型简单构造器一样:
init(parameters) { ```swift
statements init(parameters) {
} statements
}
```
便利构造器也采用相同样式的写法,但需要在`init`关键字之前放置`convenience`关键字,并使用空格将它们俩分开: 便利构造器也采用相同样式的写法,但需要在`init`关键字之前放置`convenience`关键字,并使用空格将它们俩分开:
convenience init(parameters) { ```swift
statements convenience init(parameters) {
} statements
}
```
### 指定构造器和便利构造器实战 ### 指定构造器和便利构造器实战
@ -445,15 +472,17 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
类层次中的基类是`Food`,它是一个简单的用来封装食物名字的类。`Food`类引入了一个叫做`name``String`类型属性,并且提供了两个构造器来创建`Food`实例: 类层次中的基类是`Food`,它是一个简单的用来封装食物名字的类。`Food`类引入了一个叫做`name``String`类型属性,并且提供了两个构造器来创建`Food`实例:
class Food { ```swift
var name: String class Food {
init(name: String) { var name: String
self.name = name init(name: String) {
} self.name = name
convenience init() { }
self.init(name: "[Unnamed]") convenience init() {
} self.init(name: "[Unnamed]")
} }
}
```
下图中展示了`Food`的构造器链: 下图中展示了`Food`的构造器链:
@ -461,28 +490,34 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
类没有提供一个默认的逐一成员构造器,所以`Food`类提供了一个接受单一参数`name`的指定构造器。这个构造器可以使用一个特定的名字来创建新的`Food`实例: 类没有提供一个默认的逐一成员构造器,所以`Food`类提供了一个接受单一参数`name`的指定构造器。这个构造器可以使用一个特定的名字来创建新的`Food`实例:
let namedMeat = Food(name: "Bacon") ```swift
// namedMeat 的名字是 "Bacon let namedMeat = Food(name: "Bacon")
// namedMeat 的名字是 "Bacon”
```
`Food`类中的构造器`init(name: String)`被定义为一个指定构造器,因为它能确保所有新`Food`实例的中存储型属性都被初始化。`Food`类没有父类,所以`init(name: String)`构造器不需要调用`super.init()`来完成构造。 `Food`类中的构造器`init(name: String)`被定义为一个指定构造器,因为它能确保所有新`Food`实例的中存储型属性都被初始化。`Food`类没有父类,所以`init(name: String)`构造器不需要调用`super.init()`来完成构造。
`Food`类同样提供了一个没有参数的便利构造器 `init()`。这个`init()`构造器为新食物提供了一个默认的占位名字,通过代理调用同一类中定义的指定构造器`init(name: String)`并给参数`name`传值`[Unnamed]`来实现: `Food`类同样提供了一个没有参数的便利构造器 `init()`。这个`init()`构造器为新食物提供了一个默认的占位名字,通过代理调用同一类中定义的指定构造器`init(name: String)`并给参数`name`传值`[Unnamed]`来实现:
let mysteryMeat = Food() ```swift
// mysteryMeat 的名字是 [Unnamed] let mysteryMeat = Food()
// mysteryMeat 的名字是 [Unnamed]
```
类层级中的第二个类是`Food`的子类`RecipeIngredient``RecipeIngredient`类构建了食谱中的一味调味剂。它引入了`Int`类型的数量属性`quantity`(以及从`Food`继承过来的`name`属性),并且定义了两个构造器来创建`RecipeIngredient`实例: 类层级中的第二个类是`Food`的子类`RecipeIngredient``RecipeIngredient`类构建了食谱中的一味调味剂。它引入了`Int`类型的数量属性`quantity`(以及从`Food`继承过来的`name`属性),并且定义了两个构造器来创建`RecipeIngredient`实例:
class RecipeIngredient: Food { ```swift
var quantity: Int class RecipeIngredient: Food {
init(name: String, quantity: Int) { var quantity: Int
self.quantity = quantity init(name: String, quantity: Int) {
super.init(name: name) self.quantity = quantity
} super.init(name: name)
convenience init(name: String) { }
self.init(name: name, quantity: 1) convenience init(name: String) {
} self.init(name: name, quantity: 1)
} }
}
```
下图中展示了`RecipeIngredient`类的构造器链: 下图中展示了`RecipeIngredient`类的构造器链:
@ -498,25 +533,28 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
所有的这三种构造器都可以用来创建新的`RecipeIngredient`实例: 所有的这三种构造器都可以用来创建新的`RecipeIngredient`实例:
let oneMysteryItem = RecipeIngredient() ```swift
let oneBacon = RecipeIngredient(name: "Bacon") let oneMysteryItem = RecipeIngredient()
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6) let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
```
类层级中第三个也是最后一个类是`RecipeIngredient`的子类,叫做`ShoppingListItem`。这个类构建了购物单中出现的某一种调味料。 类层级中第三个也是最后一个类是`RecipeIngredient`的子类,叫做`ShoppingListItem`。这个类构建了购物单中出现的某一种调味料。
购物单中的每一项总是从`unpurchased`未购买状态开始的。为了展现这一事实,`ShoppingListItem`引入了一个布尔类型的属性`purchased`,它的默认值是`false``ShoppingListItem`还添加了一个计算型属性`description`,它提供了关于`ShoppingListItem`实例的一些文字描述: 购物单中的每一项总是从`unpurchased`未购买状态开始的。为了展现这一事实,`ShoppingListItem`引入了一个布尔类型的属性`purchased`,它的默认值是`false``ShoppingListItem`还添加了一个计算型属性`description`,它提供了关于`ShoppingListItem`实例的一些文字描述:
class ShoppingListItem: RecipeIngredient { ```swift
var purchased = false class ShoppingListItem: RecipeIngredient {
var description: String { var purchased = false
var output = "\(quantity) x \(name.lowercaseString)" var description: String {
output += purchased ? " ✔" : " ✘" var output = "\(quantity) x \(name.lowercaseString)"
return output output += purchased ? " ✔" : " ✘"
} return output
} }
}
```
> 注意: > 注意:
>
`ShoppingListItem`没有定义构造器来为`purchased`提供初始化值,这是因为任何添加到购物单的项的初始状态总是未购买。 `ShoppingListItem`没有定义构造器来为`purchased`提供初始化值,这是因为任何添加到购物单的项的初始状态总是未购买。
由于它为自己引入的所有属性都提供了默认值,并且自己没有定义任何构造器,`ShoppingListItem`将自动继承所有父类中的指定构造器和便利构造器。 由于它为自己引入的所有属性都提供了默认值,并且自己没有定义任何构造器,`ShoppingListItem`将自动继承所有父类中的指定构造器和便利构造器。
@ -527,19 +565,21 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
你可以使用全部三个继承来的构造器来创建`ShoppingListItem`的新实例: 你可以使用全部三个继承来的构造器来创建`ShoppingListItem`的新实例:
var breakfastList = [ ```swift
ShoppingListItem(), var breakfastList = [
ShoppingListItem(name: "Bacon"), ShoppingListItem(),
ShoppingListItem(name: "Eggs", quantity: 6), ShoppingListItem(name: "Bacon"),
] ShoppingListItem(name: "Eggs", quantity: 6),
breakfastList[0].name = "Orange juice" ]
breakfastList[0].purchased = true breakfastList[0].name = "Orange juice"
for item in breakfastList { breakfastList[0].purchased = true
println(item.description) for item in breakfastList {
} println(item.description)
// 1 x orange juice ✔ }
// 1 x bacon ✘ // 1 x orange juice ✔
// 6 x eggs // 1 x bacon
// 6 x eggs ✘
```
如上所述,例子中通过字面量方式创建了一个新数组`breakfastList`,它包含了三个新的`ShoppingListItem`实例,因此数组的类型也能自动推导为`ShoppingListItem[]`。在数组创建完之后,数组中第一个`ShoppingListItem`实例的名字从`[Unnamed]`修改为`Orange juice`,并标记为已购买。接下来通过遍历数组每个元素并打印它们的描述值,展示了所有项当前的默认状态都已按照预期完成了赋值。 如上所述,例子中通过字面量方式创建了一个新数组`breakfastList`,它包含了三个新的`ShoppingListItem`实例,因此数组的类型也能自动推导为`ShoppingListItem[]`。在数组创建完之后,数组中第一个`ShoppingListItem`实例的名字从`[Unnamed]`修改为`Orange juice`,并标记为已购买。接下来通过遍历数组每个元素并打印它们的描述值,展示了所有项当前的默认状态都已按照预期完成了赋值。
@ -552,18 +592,19 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
下面列举了闭包如何提供默认值的代码概要: 下面列举了闭包如何提供默认值的代码概要:
class SomeClass { ```swift
let someProperty: SomeType = { class SomeClass {
// 在这个闭包中给 someProperty 创建一个默认值 let someProperty: SomeType = {
// someValue 必须和 SomeType 类型相同 // 在这个闭包中给 someProperty 创建一个默认值
return someValue // someValue 必须和 SomeType 类型相同
}() return someValue
} }()
}
```
注意闭包结尾的大括号后面接了一对空的小括号。这是用来告诉 Swift 需要立刻执行此闭包。如果你忽略了这对括号,相当于是将闭包本身作为值赋值给了属性,而不是将闭包的返回值赋值给属性。 注意闭包结尾的大括号后面接了一对空的小括号。这是用来告诉 Swift 需要立刻执行此闭包。如果你忽略了这对括号,相当于是将闭包本身作为值赋值给了属性,而不是将闭包的返回值赋值给属性。
>注意: >注意:
>
如果你使用闭包来初始化属性的值,请记住在闭包执行时,实例的其它部分都还没有初始化。这意味着你不能够在闭包里访问其它的属性,就算这个属性有默认值也不允许。同样,你也不能使用隐式的`self`属性,或者调用其它的实例方法。 如果你使用闭包来初始化属性的值,请记住在闭包执行时,实例的其它部分都还没有初始化。这意味着你不能够在闭包里访问其它的属性,就算这个属性有默认值也不允许。同样,你也不能使用隐式的`self`属性,或者调用其它的实例方法。
下面例子中定义了一个结构体`Checkerboard`,它构建了西洋跳棋游戏的棋盘: 下面例子中定义了一个结构体`Checkerboard`,它构建了西洋跳棋游戏的棋盘:
@ -574,28 +615,32 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
`boardColor`数组是通过一个闭包来初始化和组装颜色值的: `boardColor`数组是通过一个闭包来初始化和组装颜色值的:
struct Checkerboard { ```swift
let boardColors: Bool[] = { struct Checkerboard {
var temporaryBoard = Bool[]() let boardColors: Bool[] = {
var isBlack = false var temporaryBoard = Bool[]()
for i in 1...10 { var isBlack = false
for j in 1...10 { for i in 1...10 {
temporaryBoard.append(isBlack) for j in 1...10 {
isBlack = !isBlack temporaryBoard.append(isBlack)
} isBlack = !isBlack
isBlack = !isBlack }
} isBlack = !isBlack
return temporaryBoard }
}() return temporaryBoard
func squareIsBlackAtRow(row: Int, column: Int) -> Bool { }()
return boardColors[(row * 10) + column] func squareIsBlackAtRow(row: Int, column: Int) -> Bool {
} return boardColors[(row * 10) + column]
} }
}
```
每当一个新的`Checkerboard`实例创建时,对应的赋值闭包会执行,一系列颜色值会被计算出来作为默认值赋值给`boardColors`。上面例子中描述的闭包将计算出棋盘中每个格子合适的颜色,将这些颜色值保存到一个临时数组`temporaryBoard`中,并在构建完成时将此数组作为闭包返回值返回。这个返回的值将保存到`boardColors`中,并可以通`squareIsBlackAtRow`这个工具函数来查询。 每当一个新的`Checkerboard`实例创建时,对应的赋值闭包会执行,一系列颜色值会被计算出来作为默认值赋值给`boardColors`。上面例子中描述的闭包将计算出棋盘中每个格子合适的颜色,将这些颜色值保存到一个临时数组`temporaryBoard`中,并在构建完成时将此数组作为闭包返回值返回。这个返回的值将保存到`boardColors`中,并可以通`squareIsBlackAtRow`这个工具函数来查询。
let board = Checkerboard() ```swift
println(board.squareIsBlackAtRow(0, column: 1)) let board = Checkerboard()
// 输出 "true" println(board.squareIsBlackAtRow(0, column: 1))
println(board.squareIsBlackAtRow(9, column: 9)) // 输出 "true"
// 输出 "false" println(board.squareIsBlackAtRow(9, column: 9))
// 输出 "false"
```

View File

@ -1,6 +1,5 @@
> 翻译bruce0505 > 翻译bruce0505
> 校对fd5788
> 校对fd5788
# 析构过程Deinitialization # 析构过程Deinitialization
@ -20,9 +19,11 @@ Swift 会自动释放不再需要的实例以释放资源。如[自动引用计
在类的定义中,每个类最多只能有一个析构函数。析构函数不带任何参数,在写法上不带括号: 在类的定义中,每个类最多只能有一个析构函数。析构函数不带任何参数,在写法上不带括号:
deinit { ```swift
// 执行析构过程 deinit {
} // 执行析构过程
}
```
析构函数是在实例释放发生前一步被自动调用。不允许主动调用自己的析构函数。子类继承了父类的析构函数,并且在子类析构函数实现的最后,父类的析构函数被自动调用。即使子类没有提供自己的析构函数,父类的析构函数也总是被调用。 析构函数是在实例释放发生前一步被自动调用。不允许主动调用自己的析构函数。子类继承了父类的析构函数,并且在子类析构函数实现的最后,父类的析构函数被自动调用。即使子类没有提供自己的析构函数,父类的析构函数也总是被调用。
@ -33,17 +34,19 @@ Swift 会自动释放不再需要的实例以释放资源。如[自动引用计
这里是一个析构函数操作的例子。这个例子是一个简单的游戏,定义了两种新类型,`Bank``Player``Bank`结构体管理一个虚拟货币的流通,在这个流通中`Bank`永远不可能拥有超过 10,000 的硬币。在这个游戏中有且只能有一个`Bank`存在,因此`Bank`由带有静态属性和静态方法的结构体实现,从而存储和管理其当前的状态。 这里是一个析构函数操作的例子。这个例子是一个简单的游戏,定义了两种新类型,`Bank``Player``Bank`结构体管理一个虚拟货币的流通,在这个流通中`Bank`永远不可能拥有超过 10,000 的硬币。在这个游戏中有且只能有一个`Bank`存在,因此`Bank`由带有静态属性和静态方法的结构体实现,从而存储和管理其当前的状态。
struct Bank { ```swift
static var coinsInBank = 10_000 struct Bank {
static func vendCoins(var numberOfCoinsToVend: Int) -> Int { static var coinsInBank = 10_000
numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank) static func vendCoins(var numberOfCoinsToVend: Int) -> Int {
coinsInBank -= numberOfCoinsToVend numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank)
return numberOfCoinsToVend coinsInBank -= numberOfCoinsToVend
} return numberOfCoinsToVend
static func receiveCoins(coins: Int) { }
static func receiveCoins(coins: Int) {
coinsInBank += coins coinsInBank += coins
} }
} }
```
`Bank`根据它的`coinsInBank`属性来跟踪当前它拥有的硬币数量。银行还提供两个方法——`vendCoins``receiveCoins`——用来处理硬币的分发和收集。 `Bank`根据它的`coinsInBank`属性来跟踪当前它拥有的硬币数量。银行还提供两个方法——`vendCoins``receiveCoins`——用来处理硬币的分发和收集。
@ -53,46 +56,54 @@ Swift 会自动释放不再需要的实例以释放资源。如[自动引用计
`Player`类描述了游戏中的一个玩家。每一个 player 在任何时刻都有一定数量的硬币存储在他们的钱包中。这通过 player 的`coinsInPurse`属性来体现: `Player`类描述了游戏中的一个玩家。每一个 player 在任何时刻都有一定数量的硬币存储在他们的钱包中。这通过 player 的`coinsInPurse`属性来体现:
class Player { ```swift
var coinsInPurse: Int class Player {
init(coins: Int) { var coinsInPurse: Int
coinsInPurse = Bank.vendCoins(coins) init(coins: Int) {
} coinsInPurse = Bank.vendCoins(coins)
func winCoins(coins: Int) { }
coinsInPurse += Bank.vendCoins(coins) func winCoins(coins: Int) {
} coinsInPurse += Bank.vendCoins(coins)
deinit { }
Bank.receiveCoins(coinsInPurse) deinit {
} Bank.receiveCoins(coinsInPurse)
} }
}
```
每个`Player`实例都由一个指定数目硬币组成的启动额度初始化,这些硬币在 bank 初始化的过程中得到。如果没有足够的硬币可用,`Player`实例可能收到比指定数目少的硬币。 每个`Player`实例都由一个指定数目硬币组成的启动额度初始化,这些硬币在 bank 初始化的过程中得到。如果没有足够的硬币可用,`Player`实例可能收到比指定数目少的硬币。
`Player`类定义了一个`winCoins`方法,该方法从银行获取一定数量的硬币,并把它们添加到玩家的钱包。`Player`类还实现了一个析构函数,这个析构函数在`Player`实例释放前一步被调用。这里析构函数只是将玩家的所有硬币都返回给银行: `Player`类定义了一个`winCoins`方法,该方法从银行获取一定数量的硬币,并把它们添加到玩家的钱包。`Player`类还实现了一个析构函数,这个析构函数在`Player`实例释放前一步被调用。这里析构函数只是将玩家的所有硬币都返回给银行:
var playerOne: Player? = Player(coins: 100) ```swift
println("A new player has joined the game with \(playerOne!.coinsInPurse) coins") var playerOne: Player? = Player(coins: 100)
// 输出 "A new player has joined the game with 100 coins" println("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
println("There are now \(Bank.coinsInBank) coins left in the bank") // 输出 "A new player has joined the game with 100 coins"
// 输出 "There are now 9900 coins left in the bank" println("There are now \(Bank.coinsInBank) coins left in the bank")
// 输出 "There are now 9900 coins left in the bank"
```
一个新的`Player`实例随着一个 100 个硬币(如果有)的请求而被创建。这`个Player`实例存储在一个名为`playerOne`的可选`Player`变量中。这里使用一个可选变量,是因为玩家可以随时离开游戏。设置为可选使得你可以跟踪当前是否有玩家在游戏中。 一个新的`Player`实例随着一个 100 个硬币(如果有)的请求而被创建。这`个Player`实例存储在一个名为`playerOne`的可选`Player`变量中。这里使用一个可选变量,是因为玩家可以随时离开游戏。设置为可选使得你可以跟踪当前是否有玩家在游戏中。
因为`playerOne`是可选的,所以由一个感叹号(`!`)来修饰,每当其`winCoins`方法被调用时,`coinsInPurse`属性被访问并打印出它的默认硬币数目。 因为`playerOne`是可选的,所以由一个感叹号(`!`)来修饰,每当其`winCoins`方法被调用时,`coinsInPurse`属性被访问并打印出它的默认硬币数目。
playerOne!.winCoins(2_000) ```swift
println("PlayerOne won 2000 coins & now has \ (playerOne!.coinsInPurse) coins") playerOne!.winCoins(2_000)
// 输出 "PlayerOne won 2000 coins & now has 2100 coins" println("PlayerOne won 2000 coins & now has \ (playerOne!.coinsInPurse) coins")
println("The bank now only has \(Bank.coinsInBank) coins left") // 输出 "PlayerOne won 2000 coins & now has 2100 coins"
// 输出 "The bank now only has 7900 coins left" println("The bank now only has \(Bank.coinsInBank) coins left")
// 输出 "The bank now only has 7900 coins left"
```
这里player 已经赢得了 2,000 硬币。player 的钱包现在有 2,100 硬币bank 只剩余 7,900 硬币。 这里player 已经赢得了 2,000 硬币。player 的钱包现在有 2,100 硬币bank 只剩余 7,900 硬币。
playerOne = nil ```swift
println("PlayerOne has left the game") playerOne = nil
// 输出 "PlayerOne has left the game" println("PlayerOne has left the game")
println("The bank now has \(Bank.coinsInBank) coins") // 输出 "PlayerOne has left the game"
// 输出 "The bank now has 10000 coins" println("The bank now has \(Bank.coinsInBank) coins")
// 输出 "The bank now has 10000 coins"
```
玩家现在已经离开了游戏。这表明是要将可选的`playerOne`变量设置为`nil`,意思是“没有`Player`实例”。当这种情况发生的时候,`playerOne`变量对`Player`实例的引用被破坏了。没有其它属性或者变量引用`Player`实例,因此为了清空它占用的内存从而释放它。在这发生前一步,其析构函数被自动调用,其硬币被返回到银行。 玩家现在已经离开了游戏。这表明是要将可选的`playerOne`变量设置为`nil`,意思是“没有`Player`实例”。当这种情况发生的时候,`playerOne`变量对`Player`实例的引用被破坏了。没有其它属性或者变量引用`Player`实例,因此为了清空它占用的内存从而释放它。在这发生前一步,其析构函数被自动调用,其硬币被返回到银行。

View File

@ -1,6 +1,6 @@
> 翻译marsprince > 翻译marsprince
> 校对numbbbbb > 校对numbbbbb, stanzhai
# 声明 # 声明
----------------- -----------------
@ -31,41 +31,24 @@
在swift中大多数声明在某种意义上讲也是执行或同事声明它们的初始化定义。这意味着因为协议和他们的成员不匹配 在swift中大多数声明在某种意义上讲也是执行或同事声明它们的初始化定义。这意味着因为协议和他们的成员不匹配
大多数协议成员需要单独的声明。为了方便起见也因为这些区别在swift里不是很重要声明语句同时包含了声明和定义。 大多数协议成员需要单独的声明。为了方便起见也因为这些区别在swift里不是很重要声明语句同时包含了声明和定义。
>GRAMMAR OF A DECLARATION > 声明语法
> *声明* → [*导入声明*](..\chapter3\05_Declarations.html#import_declaration)
>declaration → import-declaration­ > *声明* → [*常量声明*](..\chapter3\05_Declarations.html#constant_declaration)
> *声明* → [*变量声明*](..\chapter3\05_Declarations.html#variable_declaration)
>declaration → constant-declaration­ > *声明* → [*类型别名声明*](..\chapter3\05_Declarations.html#typealias_declaration)
> *声明* → [*函数声明*](..\chapter3\05_Declarations.html#function_declaration)
>declaration → variable-declaration­ > *声明* → [*枚举声明*](..\chapter3\05_Declarations.html#enum_declaration)
> *声明* → [*结构体声明*](..\chapter3\05_Declarations.html#struct_declaration)
>declaration → typealias-declaration­ > *声明* → [*类声明*](..\chapter3\05_Declarations.html#class_declaration)
> *声明* → [*协议声明*](..\chapter3\05_Declarations.html#protocol_declaration)
>declaration → function-declaration­ > *声明* → [*构造器声明*](..\chapter3\05_Declarations.html#initializer_declaration)
> *声明* → [*析构器声明*](..\chapter3\05_Declarations.html#deinitializer_declaration)
>declaration → enum-declaration­ > *声明* → [*扩展声明*](..\chapter3\05_Declarations.html#extension_declaration)
> *声明* → [*附属脚本声明*](..\chapter3\05_Declarations.html#subscript_declaration)
>declaration → struct-declaration­ > *声明* → [*运算符声明*](..\chapter3\05_Declarations.html#operator_declaration)
> *声明(Declarations)列表* → [*声明*](..\chapter3\05_Declarations.html#declaration) [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_
>declaration → class-declaration­ > *声明描述符(Specifiers)列表* → [*声明描述符(Specifier)*](..\chapter3\05_Declarations.html#declaration_specifier) [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_
> *声明描述符(Specifier)* → **class** | **mutating** | **nonmutating** | **override** | **static** | **unowned** | **unowned(safe)** | **unowned(unsafe)** | **weak**
>declaration → protocol-declaration­
> declaration → initializer-declaration­
>declaration → deinitializer-declaration­
> declaration → extension-declaration­
> declaration → subscript-declaration­
>declaration → operator-declaration­
>declarations → declaration­declarations­opt­
>declaration-specifiers → declaration-specifier­declaration-specifiers­opt­
>declaration-specifier → class­ | mutating ­| nonmutating­ | override­ | static­ | unowned |
<a name="module_scope"></a> <a name="module_scope"></a>
##模块范围 ##模块范围
@ -73,9 +56,8 @@
模块范围定义了对模块中其他源文件可见的代码。待改进在swift的源文件中最高级别的代码由零个或多个语句 模块范围定义了对模块中其他源文件可见的代码。待改进在swift的源文件中最高级别的代码由零个或多个语句
声明和表达组成。变量,常量和其他的声明语句在一个源文件的最顶级被声明,使得他们对同一模块中的每个源文件都是可见的。 声明和表达组成。变量,常量和其他的声明语句在一个源文件的最顶级被声明,使得他们对同一模块中的每个源文件都是可见的。
>GRAMMAR OF A TOP-LEVEL DECLARATION > 顶级(Top Level) 声明语法
> *顶级声明* → [*多条语句(Statements)*](..\chapter3\10_Statements.html#statements) _可选_
>top-level-declaration → statements ­opt
<a name="code_blocks"></a> <a name="code_blocks"></a>
##代码块 ##代码块
@ -88,9 +70,8 @@
代码块中的语句包括声明,表达式和各种其他类型的语句,它们按照在源码中的出现顺序被依次执行。 代码块中的语句包括声明,表达式和各种其他类型的语句,它们按照在源码中的出现顺序被依次执行。
>GRAMMAR OF A CODE BLOCK > 代码块语法
> *代码块* → **{** [*多条语句(Statements)*](..\chapter3\10_Statements.html#statements) _可选_ **}**
>code-block → ­statements ­opt­
<a name="import_declaration"></a> <a name="import_declaration"></a>
##引入声明 ##引入声明
@ -106,12 +87,11 @@
import import kind module.symbol name import import kind module.symbol name
import module.submodule import module.submodule
>GRAMMAR OF AN IMPORT DECLARATION > 导入(Import)声明语法
> *导入声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **import** [*导入类型*](..\chapter3\05_Declarations.html#import_kind) _可选_ [*导入路径*](..\chapter3\05_Declarations.html#import_path)
>import-declaration → attributes ­opt ­import­ import-kind­ opt import-path­ > *导入类型* → **typealias** | **struct** | **class** | **enum** | **protocol** | **var** | **func**
>import-kind → typealias­ | struct­ | class­ | enum­ | protocol­ | var­ | func­ > *导入路径* → [*导入路径标识符*](..\chapter3\05_Declarations.html#import_path_identifier) | [*导入路径标识符*](..\chapter3\05_Declarations.html#import_path_identifier) **.** [*导入路径*](..\chapter3\05_Declarations.html#import_path)
>import-path → import-path-identifier­ import-path-identifier­.­import-path­ > *导入路径标识符* → [*标识符*](LexicalStructure.html#identifier) | [*运算符*](LexicalStructure.html#operator)
>import-path-identifier → identifier­ operator
<a name="constant_declaration"></a> <a name="constant_declaration"></a>
##常量声明 ##常量声明
@ -131,10 +111,10 @@
在上例中firstNumber是一个值为10的常量secnodeName是一个值为42的常量。所有常量都可以独立的使用 在上例中firstNumber是一个值为10的常量secnodeName是一个值为42的常量。所有常量都可以独立的使用
1 println("The first number is \(firstNumber).") println("The first number is \(firstNumber).")
2 // prints "The first number is 10." // prints "The first number is 10."
3 println("The second number is \(secondNumber).") println("The second number is \(secondNumber).")
4 // prints "The second number is 42." // prints "The second number is 42."
类型注释(:type在常量声明中是一个可选项它可以用来描述在类型接口type inference中找到的类型。 类型注释(:type在常量声明中是一个可选项它可以用来描述在类型接口type inference中找到的类型。
@ -143,12 +123,11 @@
如果还想获得更多关于常量的信息或者想在使用中获得帮助请查看常量和变量constants and variables, 如果还想获得更多关于常量的信息或者想在使用中获得帮助请查看常量和变量constants and variables,
存储属性stored properties等节。 存储属性stored properties等节。
>GRAMMAR OF A CONSTANT DECLARATION > 常数声明语法
> *常量声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **let** [*模式构造器列表*](..\chapter3\05_Declarations.html#pattern_initializer_list)
>constant-declaration → attributes­ opt ­declaration-specifiers­ opt ­let­pattern-initializer-list­ > *模式构造器列表* → [*模式构造器*](..\chapter3\05_Declarations.html#pattern_initializer) | [*模式构造器*](..\chapter3\05_Declarations.html#pattern_initializer) **,** [*模式构造器列表*](..\chapter3\05_Declarations.html#pattern_initializer_list)
>pattern-initializer-list → pattern-initializer­ | pattern-initializer­ , pattern-initializer-list­ > *模式构造器* → [*模式*](..\chapter3\07_Patterns.html#pattern) [*构造器*](..\chapter3\05_Declarations.html#initializer) _可选_
>pattern-initializer → pattern ­initializer ­opt­ > *构造器* → **=** [*表达式*](..\chapter3\04_Expressions.html#expression)
>initializer → =­expression
<a name="variable_declaration"></a> <a name="variable_declaration"></a>
##变量声明 ##变量声明
@ -246,47 +225,27 @@ willset监视器初始名为newvaluedidset监视器初始名为oldvalue。
class关键字用来声明类的计算型属性。static关键字用来声明类的静态变量属性。类和静态变量在类型属性(type properties)中有详细讨论。 class关键字用来声明类的计算型属性。static关键字用来声明类的静态变量属性。类和静态变量在类型属性(type properties)中有详细讨论。
>GRAMMAR OF A VARIABLE DECLARATION > 变量声明语法
> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*模式构造器列表*](..\chapter3\05_Declarations.html#pattern_initializer_list)
>variable-declarationvariable-declaration-head­pattern-initializer-list­ > *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*代码块*](..\chapter3\05_Declarations.html#code_block)
> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*getter-setter块*](..\chapter3\05_Declarations.html#getter_setter_block)
>variable-declarationvariable-declaration-head ­variable-name ­type-annotation ­code-block­ > *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*getter-setter关键字(Keyword)块*](..\chapter3\05_Declarations.html#getter_setter_keyword_block)
> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*构造器*](..\chapter3\05_Declarations.html#initializer) _可选_ [*willSet-didSet代码块*](..\chapter3\05_Declarations.html#willSet_didSet_block)
>variable-declaration → variable-declaration-head ­variable-name ­type-annotation ­getter-setter-block­ > *变量声明头(Head)* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **var**
> *变量名称* → [*标识符*](LexicalStructure.html#identifier)
>variable-declaration → variable-declaration-head ­variable-name­ type-annotation ­getter-setter-keyword-block­ > *getter-setter块* → **{** [*getter子句*](..\chapter3\05_Declarations.html#getter_clause) [*setter子句*](..\chapter3\05_Declarations.html#setter_clause) _可选_ **}**
> *getter-setter块* → **{** [*setter子句*](..\chapter3\05_Declarations.html#setter_clause) [*getter子句*](..\chapter3\05_Declarations.html#getter_clause) **}**
> variable-declaration → variable-declaration-head­ variable-name ­type-annotation­initializer­ opt ­willSet-didSet-block­ > *getter子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **get** [*代码块*](..\chapter3\05_Declarations.html#code_block)
> *setter子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **set** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block)
>variable-declaration-head → attributes ­opt­ declaration-specifiers ­opt ­var > *setter名称* → **(** [*标识符*](LexicalStructure.html#identifier) **)**
­ > *getter-setter关键字(Keyword)块* → **{** [*getter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#getter_keyword_clause) [*setter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#setter_keyword_clause) _可选_ **}**
>variable-name → identifier­ > *getter-setter关键字(Keyword)块* → **{** [*setter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#setter_keyword_clause) [*getter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#getter_keyword_clause) **}**
> *getter关键字(Keyword)子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **get**
>getter-setter-block → {­getter-clause ­setter-clause­ opt­}­ > *setter关键字(Keyword)子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **set**
> *willSet-didSet代码块* → **{** [*willSet子句*](..\chapter3\05_Declarations.html#willSet_clause) [*didSet子句*](..\chapter3\05_Declarations.html#didSet_clause) _可选_ **}**
>getter-setter-block → {­setter-clause ­getter-clause­}­ > *willSet-didSet代码块* → **{** [*didSet子句*](..\chapter3\05_Declarations.html#didSet_clause) [*willSet子句*](..\chapter3\05_Declarations.html#willSet_clause) **}**
> *willSet子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **willSet** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block)
>getter-clause → attributes ­opt­get­code-block­ > *didSet子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **didSet** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block)
>setter-clause → attributes ­opt ­set­ setter-name­ opt­ code-block­
>setter-name → (­identifier­)­
>getter-setter-keyword-block → {­getter-keyword-clause ­setter-keyword-clause­ opt­}
­
>getter-setter-keyword-block → {­setter-keyword-clause ­getter-keyword-clause­}
>getter-keyword-clause → attributes­ opt­ get­
>setter-keyword-clause → attributes ­opt­ set­
>willSet-didSet-block → {­willSet-clause ­didSet-clause ­opt­}­
>willSet-didSet-block → {­didSet-clause ­willSet-clause­}­
>willSet-clause → attributes ­opt ­willSet ­setter-name­ opt ­code-block­
>didSet-clause → attributes ­opt ­didSet ­setter-name ­opt­ code-block­
<a name="type_alias_declaration"></a> <a name="type_alias_declaration"></a>
##类型的别名声明 ##类型的别名声明
@ -301,12 +260,11 @@ class关键字用来声明类的计算型属性。static关键字用来声明类
查看更多Protocol Associated Type Declaration. 查看更多Protocol Associated Type Declaration.
>GRAMMAR OF A TYPE ALIAS DECLARATION > 类型别名声明语法
> *类型别名声明* → [*类型别名头(Head)*](..\chapter3\05_Declarations.html#typealias_head) [*类型别名赋值*](..\chapter3\05_Declarations.html#typealias_assignment)
> typealias-declaration → typealias-head­ typealias-assignment > *类型别名头(Head)* → **typealias** [*类型别名名称*](..\chapter3\05_Declarations.html#typealias_name)
> typealias-head → typealias­ typealias-name > *类型别名名称* → [*标识符*](LexicalStructure.html#identifier)
> typealias-name → identifier > *类型别名赋值* → **=** [*类型*](..\chapter3\03_Types.html#type)
> typealias-assignment → =type
<a name="function_declaration"></a> <a name="function_declaration"></a>
##函数声明 ##函数声明
@ -420,23 +378,22 @@ f()和f(x:7)都是只有一个变量x的函数的有效调用但是f(7)是非
多级柯里化应用如下 多级柯里化应用如下
>GRAMMAR OF A FUNCTION DECLARATION > 函数声明语法
> *函数声明* → [*函数头*](..\chapter3\05_Declarations.html#function_head) [*函数名*](..\chapter3\05_Declarations.html#function_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*函数签名(Signature)*](..\chapter3\05_Declarations.html#function_signature) [*函数体*](..\chapter3\05_Declarations.html#function_body)
>function-declaration → function-head­ function-name­ generic-parameter-clause ­opt­function-signature­ function-body­ > *函数头* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **func**
> function-head → attributes ­opt ­declaration-specifiers ­opt ­func­ > *函数名* → [*标识符*](LexicalStructure.html#identifier) | [*运算符*](LexicalStructure.html#operator)
> function-name → identifier­ operator­ > *函数签名(Signature)* → [*parameter-clauses*](..\chapter3\05_Declarations.html#parameter_clauses) [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_
>function-signature → parameter-clauses ­function-result ­opt­ > *函数结果* → **->** [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type)
> function-result → ->­attributes ­opt ­type­ > *函数体* → [*代码块*](..\chapter3\05_Declarations.html#code_block)
> function-body → code-block­ > *parameter-clauses* → [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause) [*parameter-clauses*](..\chapter3\05_Declarations.html#parameter_clauses) _可选_
> parameter-clauses → parameter-clause ­parameter-clauses ­opt­ > *参数子句* → **(** **)** | **(** [*参数列表*](..\chapter3\05_Declarations.html#parameter_list) **...** _可选_ **)**
> parameter-clause → (­)­ (­parameter-list­...­opt­)­ > *参数列表* → [*参数*](..\chapter3\05_Declarations.html#parameter) | [*参数*](..\chapter3\05_Declarations.html#parameter) **,** [*参数列表*](..\chapter3\05_Declarations.html#parameter_list)
> parameter-list → parameter­ parameter­,­parameter-list­ > *参数* → **inout** _可选_ **let** _可选_ **#** _可选_ [*参数名*](..\chapter3\05_Declarations.html#parameter_name) [*本地参数名*](..\chapter3\05_Declarations.html#local_parameter_name) _可选_ [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*默认参数子句*](..\chapter3\05_Declarations.html#default_argument_clause) _可选_
> parameter → inout ­opt ­let ­opt­#­opt­parameter-name local-parameter-name ­opt­ type-annotation ­default-argument-clause ­opt­ > *参数***inout** _可选_ **var** **#** _可选_ [*参数名*](..\chapter3\05_Declarations.html#parameter_name) [*本地参数名*](..\chapter3\05_Declarations.html#local_parameter_name) _可选_ [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*默认参数子句*](..\chapter3\05_Declarations.html#default_argument_clause) _可选_
> parameter → inout­opt­var­#­opt­parameter-name­local-parameter-name ­opt­ type-annotation­default-argument-clause ­opt­ > *参数* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type)
> parameter → attributes ­opt ­type­ > *参数名* → [*标识符*](LexicalStructure.html#identifier) | **_**
> parameter-name → identifier­ _­ > *本地参数名* → [*标识符*](LexicalStructure.html#identifier) | **_**
> local-parameter-name → identifier­ _­ > *默认参数子句* → **=** [*表达式*](..\chapter3\04_Expressions.html#expression)
> default-argument-clause → =­expression­
<a name="enumeration_declaration"></a> <a name="enumeration_declaration"></a>
##枚举声明 ##枚举声明
@ -505,24 +462,23 @@ ExampleEnum.D的值会自动增长为6.
枚举类型是模式匹配(pattern-matched)的和其相反的是switch语句case块中枚举事件匹配在枚举事件类型(Enumeration Case Pattern)中有描述。 枚举类型是模式匹配(pattern-matched)的和其相反的是switch语句case块中枚举事件匹配在枚举事件类型(Enumeration Case Pattern)中有描述。
>GRAMMAR OF AN ENUMERATION DECLARATION > 枚举声明语法
> *枚举声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*联合式枚举*](..\chapter3\05_Declarations.html#union_style_enum) | [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*原始值式枚举*](..\chapter3\05_Declarations.html#raw_value_style_enum)
> enum-declaration → attributes­opt­union-style-enum­ attributes­opt­raw-value-style-enum­ > *联合式枚举* → [*枚举名*](..\chapter3\05_Declarations.html#enum_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ **{** [*union-style-enum-members*](..\chapter3\05_Declarations.html#union_style_enum_members) _可选_ **}**
> union-style-enum → enum-name­generic-parameter-clause­opt­{­union-style-enum-members­opt­}­ > *union-style-enum-members* → [*union-style-enum-member*](..\chapter3\05_Declarations.html#union_style_enum_member) [*union-style-enum-members*](..\chapter3\05_Declarations.html#union_style_enum_members) _可选_
union-style-enum-membersunion-style-enum-member­union-style-enum-members­opt­ > *union-style-enum-member*[*声明*](..\chapter3\05_Declarations.html#declaration) | [*联合式(Union Style)的枚举case子句*](..\chapter3\05_Declarations.html#union_style_enum_case_clause)
union-style-enum-member → declaration­ union-style-enum-case-clause­ > *联合式(Union Style)的枚举case子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **case** [*联合式(Union Style)的枚举case列表*](..\chapter3\05_Declarations.html#union_style_enum_case_list)
union-style-enum-case-clause → attributes­opt­case­union-style-enum-case-list­ > *联合式(Union Style)的枚举case列表* → [*联合式(Union Style)的case*](..\chapter3\05_Declarations.html#union_style_enum_case) | [*联合式(Union Style)的case*](..\chapter3\05_Declarations.html#union_style_enum_case) **,** [*联合式(Union Style)的枚举case列表*](..\chapter3\05_Declarations.html#union_style_enum_case_list)
union-style-enum-case-list → union-style-enum-case­ union-style-enum-case­,­union-style-enum-case-list­ > *联合式(Union Style)的case* → [*枚举的case名*](..\chapter3\05_Declarations.html#enum_case_name) [*元组类型*](..\chapter3\03_Types.html#tuple_type) _可选_
union-style-enum-case → enum-case-name­tuple-type­opt­ > *枚举名* → [*标识符*](LexicalStructure.html#identifier)
enum-name → identifier­ > *枚举的case名* → [*标识符*](LexicalStructure.html#identifier)
enum-case-name → identifier­ > *原始值式枚举* → [*枚举名*](..\chapter3\05_Declarations.html#enum_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ **:** [*类型标识*](..\chapter3\03_Types.html#type_identifier) **{** [*原始值式枚举成员列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_members) _可选_ **}**
raw-value-style-enum → enum-name­generic-parameter-clause­opt­:­type-identifier­{­raw-value-style-enum-members­opt­}­ > *原始值式枚举成员列表* → [*原始值式枚举成员*](..\chapter3\05_Declarations.html#raw_value_style_enum_member) [*原始值式枚举成员列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_members) _可选_
raw-value-style-enum-members → raw-value-style-enum-member­raw-value-style-enum-members­opt­ > *原始值式枚举成员* → [*声明*](..\chapter3\05_Declarations.html#declaration) | [*原始值式枚举case子句*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_clause)
raw-value-style-enum-member → declaration­ raw-value-style-enum-case-clause­ > *原始值式枚举case子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **case** [*原始值式枚举case列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_list)
raw-value-style-enum-case-clause → attributes­opt­case­raw-value-style-enum-case-list­ > *原始值式枚举case列表* → [*原始值式枚举case*](..\chapter3\05_Declarations.html#raw_value_style_enum_case) | [*原始值式枚举case*](..\chapter3\05_Declarations.html#raw_value_style_enum_case) **,** [*原始值式枚举case列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_list)
raw-value-style-enum-case-list → raw-value-style-enum-case­ raw-value-style-enum-case­,­raw-value-style-enum-case-list­ > *原始值式枚举case* → [*枚举的case名*](..\chapter3\05_Declarations.html#enum_case_name) [*原始值赋值*](..\chapter3\05_Declarations.html#raw_value_assignment) _可选_
raw-value-style-enum-case → enum-case-name­raw-value-assignment­opt­ > *原始值赋值* → **=** [*字面量*](LexicalStructure.html#literal)
raw-value-assignment → =­literal­
<a name="structure_declaration"></a> <a name="structure_declaration"></a>
##结构体声明 ##结构体声明
@ -556,11 +512,10 @@ ExampleEnum.D的值会自动增长为6.
你可以使用扩展声明来扩展结构体类型的行为,参见扩展声明(Extension Declaration). 你可以使用扩展声明来扩展结构体类型的行为,参见扩展声明(Extension Declaration).
>GRAMMAR OF A STRUCTURE DECLARATION > 结构体声明语法
> *结构体声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **struct** [*结构体名称*](..\chapter3\05_Declarations.html#struct_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*结构体主体*](..\chapter3\05_Declarations.html#struct_body)
> struct-declaration → attributes­opt­struct­struct-name­generic-parameter-clause­opt­type-inheritance-clause­opt­struct-body­ > *结构体名称* → [*标识符*](LexicalStructure.html#identifier)
> struct-name → identifier­ > *结构体主体* → **{** [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_ **}**
> struct-body → {­declarations­opt­}
<a name="class_declaration"></a> <a name="class_declaration"></a>
##类声明 ##类声明
@ -599,11 +554,10 @@ ExampleEnum.D的值会自动增长为6.
你可以使用扩展声明来扩展类的行为,参见扩展声明(Extension Declaration). 你可以使用扩展声明来扩展类的行为,参见扩展声明(Extension Declaration).
> GRAMMAR OF A CLASS DECLARATION > 类声明语法
> *类声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **class** [*类名*](..\chapter3\05_Declarations.html#class_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*类主体*](..\chapter3\05_Declarations.html#class_body)
> class-declaration → attributes­opt­class­class-name­generic-parameter-clause­opt­type-inheritance-clause­opt­class-body­ > *类名* → [*标识符*](LexicalStructure.html#identifier)
> class-name → identifier­ > *类主体* → **{** [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_ **}**
> class-body → {­declarations­opt­}
<a name="protocol_declaration"></a> <a name="protocol_declaration"></a>
##协议声明(translated by 小一) ##协议声明(translated by 小一)
@ -638,25 +592,23 @@ protocol protocol name: inherited protocols {
你可以使用协议来声明一个类的代理的方法或者应该实现的结构,就像[委托(代理)模式](../chapter2/21_Protocols.html#delegation)描述的那样。 你可以使用协议来声明一个类的代理的方法或者应该实现的结构,就像[委托(代理)模式](../chapter2/21_Protocols.html#delegation)描述的那样。
>协议声明语法 > 协议(Protocol)声明语法
protocol-declaration → attributes­opt­protocol­protocol-name­type-inheritance-clause­opt­protocol-body­ > *协议声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **protocol** [*协议名*](..\chapter3\05_Declarations.html#protocol_name) [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*协议主体*](..\chapter3\05_Declarations.html#protocol_body)
protocol-name → identifier­ > *协议名* → [*标识符*](LexicalStructure.html#identifier)
protocol-body → {­protocol-member-declarations­opt­}­ > *协议主体* → **{** [*协议成员声明(Declarations)列表*](..\chapter3\05_Declarations.html#protocol_member_declarations) _可选_ **}**
protocol-member-declarationprotocol-property-declaration­ > *协议成员声明* → [*协议属性声明*](..\chapter3\05_Declarations.html#protocol_property_declaration)
protocol-member-declarationprotocol-method-declaration­ > *协议成员声明* → [*协议方法声明*](..\chapter3\05_Declarations.html#protocol_method_declaration)
protocol-member-declarationprotocol-initializer-declaration­ > *协议成员声明* → [*协议构造器声明*](..\chapter3\05_Declarations.html#protocol_initializer_declaration)
protocol-member-declarationprotocol-subscript-declaration­ > *协议成员声明* → [*协议附属脚本声明*](..\chapter3\05_Declarations.html#protocol_subscript_declaration)
protocol-member-declarationprotocol-associated-type-declaration­ > *协议成员声明* → [*协议关联类型声明*](..\chapter3\05_Declarations.html#protocol_associated_type_declaration)
protocol-member-declarationsprotocol-member-declaration­protocol-member-declarations­opt­ > *协议成员声明(Declarations)列表* → [*协议成员声明*](..\chapter3\05_Declarations.html#protocol_member_declaration) [*协议成员声明(Declarations)列表*](..\chapter3\05_Declarations.html#protocol_member_declarations) _可选_
<a name="protocol_property_declaration"></a> <a name="protocol_property_declaration"></a>
###协议属性声明 ###协议属性声明
协议声明了一致性类型必须在协议声明的主体里通过引入一个协议属性声明来实现一个属性。协议属性声明有一种特殊的类型声明形式: 协议声明了一致性类型必须在协议声明的主体里通过引入一个协议属性声明来实现一个属性。协议属性声明有一种特殊的类型声明形式:
```javascript var property name: type { get set }
var property name: type { get set }
```
同其它协议成员声明一样,这些属性声明仅仅针对符合该协议的类型声明了`getter``setter`要求。结果就是你不需要在协议里它被声明的地方实现`getter``setter` 同其它协议成员声明一样,这些属性声明仅仅针对符合该协议的类型声明了`getter``setter`要求。结果就是你不需要在协议里它被声明的地方实现`getter``setter`
@ -664,8 +616,8 @@ var property name: type { get set }
更多参见[变量声明](../chapter3/05_Declarations.html#variable_declaration) 更多参见[变量声明](../chapter3/05_Declarations.html#variable_declaration)
>协议属性声明语法 > 协议属性声明语法
protocol-property-declarationvariable-declaration-head­variable-name­type-annotation­getter-setter-keyword-block­ > *协议属性声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*getter-setter关键字(Keyword)块*](..\chapter3\05_Declarations.html#getter_setter_keyword_block)
###协议方法声明 ###协议方法声明
@ -679,9 +631,8 @@ protocol-property-declaration → variable-declaration-head­variable-name­type
更多请参阅函数声明。 更多请参阅函数声明。
>GRAMMAR OF A PROTOCOL METHOD DECLARATION > 协议方法声明语法
> *协议方法声明* → [*函数头*](..\chapter3\05_Declarations.html#function_head) [*函数名*](..\chapter3\05_Declarations.html#function_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*函数签名(Signature)*](..\chapter3\05_Declarations.html#function_signature)
>protocol-method-declaration → function-head­function-name­generic-parameter-clause­opt­function-signature­
###协议构造器声明 ###协议构造器声明
@ -690,16 +641,15 @@ protocol-property-declaration → variable-declaration-head­variable-name­type
更多请参阅构造器声明。 更多请参阅构造器声明。
>GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION > 协议构造器声明语法
> *协议构造器声明* → [*构造器头(Head)*](..\chapter3\05_Declarations.html#initializer_head) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause)
>protocol-initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­
###协议附属脚本声明 ###协议附属脚本声明
协议声明了一致性类型必须在协议声明的主体里通过引入一个协议附属脚本声明来实现一个附属脚本。协议属性声明 协议声明了一致性类型必须在协议声明的主体里通过引入一个协议附属脚本声明来实现一个附属脚本。协议属性声明
对附属脚本声明有一个特殊的形式: 对附属脚本声明有一个特殊的形式:
>subscript (parameters) -> return type { get set } subscript (parameters) -> return type { get set }
附属脚本声明只为和协议一致的类型声明了必需的最小数量的的getter和setter。如果附属脚本申明包含get和set关键字 附属脚本声明只为和协议一致的类型声明了必需的最小数量的的getter和setter。如果附属脚本申明包含get和set关键字
一致的类型也必须有一个getter和setter语句。如果附属脚本声明值包含get关键字一致的类型必须至少包含一个 一致的类型也必须有一个getter和setter语句。如果附属脚本声明值包含get关键字一致的类型必须至少包含一个
@ -707,9 +657,8 @@ getter语句可以选择是否包含setter语句。
更多参阅附属脚本声明。 更多参阅附属脚本声明。
>GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION > 协议附属脚本声明语法
> *协议附属脚本声明* → [*附属脚本头(Head)*](..\chapter3\05_Declarations.html#subscript_head) [*附属脚本结果(Result)*](..\chapter3\05_Declarations.html#subscript_result) [*getter-setter关键字(Keyword)块*](..\chapter3\05_Declarations.html#getter_setter_keyword_block)
>protocol-subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­
###协议相关类型声明 ###协议相关类型声明
@ -717,9 +666,8 @@ getter语句可以选择是否包含setter语句。
语句中的类型参数很相似但是它们在声明的协议中包含self关键字。在这些语句中self指代和协议一致的可能的类型。 语句中的类型参数很相似但是它们在声明的协议中包含self关键字。在这些语句中self指代和协议一致的可能的类型。
获得更多信息和例子,查看相关类型或类型别名声明。 获得更多信息和例子,查看相关类型或类型别名声明。
>GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION > 协议关联类型声明语法
> *协议关联类型声明* → [*类型别名头(Head)*](..\chapter3\05_Declarations.html#typealias_head) [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*类型别名赋值*](..\chapter3\05_Declarations.html#typealias_assignment) _可选_
>protocol-associated-type-declaration → typealias-head­type-inheritance-clause­opt­typealias-assignment­opt­
<a name="initializer_declaration"></a> <a name="initializer_declaration"></a>
##构造器声明 ##构造器声明
@ -759,11 +707,10 @@ overrride关键字。
查看更多关于不同声明方法的构造器的例子,参阅构造过程一节。 查看更多关于不同声明方法的构造器的例子,参阅构造过程一节。
>GRAMMAR OF AN INITIALIZER DECLARATION > 构造器声明语法
> *构造器声明* → [*构造器头(Head)*](..\chapter3\05_Declarations.html#initializer_head) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause) [*构造器主体*](..\chapter3\05_Declarations.html#initializer_body)
>initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­initializer-body­ > *构造器头(Head)* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **convenience** _可选_ **init**
>initializer-head → attributes­opt­convenience­opt­init­ > *构造器主体* → [*代码块*](..\chapter3\05_Declarations.html#code_block)
>initializer-body → code-block­
<a name="deinitializer_declaration"></a> <a name="deinitializer_declaration"></a>
##析构声明 ##析构声明
@ -781,12 +728,10 @@ overrride关键字。
析构器不会被直接调用。 析构器不会被直接调用。
查看例子和如何在类的声明中使用析构器,参见析构过程一节 查看例子和如何在类的声明中使用析构器,参见析构过程一节
>GRAMMAR OF A DEINITIALIZER DECLARATION > 析构器声明语法
> *析构器声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **deinit** [*代码块*](..\chapter3\05_Declarations.html#code_block)
>deinitializer-declaration → attributes­opt­deinit­code-block
<a name="extension_declaration"></a> <a name="extension_declaration"></a>
##扩展声明 ##扩展声明
@ -809,23 +754,23 @@ type-inheritance-clause是一个只包含协议列表的扩展声明。
扩展声明可以包含构造器声明,这意味着,如果你扩展的类型在其他模块中定义,构造器声明必须委托另一个在 扩展声明可以包含构造器声明,这意味着,如果你扩展的类型在其他模块中定义,构造器声明必须委托另一个在
那个模块里声明的构造器来恰当的初始化。 那个模块里声明的构造器来恰当的初始化。
>GRAMMAR OF AN EXTENSION DECLARATION > 扩展(Extension)声明语法
> *扩展声明* → **extension** [*类型标识*](..\chapter3\03_Types.html#type_identifier) [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*extension-body*](..\chapter3\05_Declarations.html#extension_body)
>extension-declaration → extension­type-identifier­type-inheritance-clause­opt­extension-body­ > *extension-body* → **{** [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_ **}**
>extension-body → {­declarations­opt­}­
<a name="subscript_declaration"></a> <a name="subscript_declaration"></a>
##附属脚本声明(translated by 林) ##附属脚本声明(translated by 林)
附属脚本用于向特定类型添加附属脚本支持,通常为访问集合,列表和序列的元素时提供语法便利。附属脚本声明使用关键字`subscript`,声明形式如下: 附属脚本用于向特定类型添加附属脚本支持,通常为访问集合,列表和序列的元素时提供语法便利。附属脚本声明使用关键字`subscript`,声明形式如下:
> subscript (`parameter`) -> (return type){ > subscript (`parameter`) -> (return type){
get{ get{
`statements` `statements`
} }
set(`setter name`){ set(`setter name`){
`statements` `statements`
} }
} }
附属脚本声明只能在类,结构体,枚举,扩展和协议声明的上下文进行声明。 附属脚本声明只能在类,结构体,枚举,扩展和协议声明的上下文进行声明。
_变量(parameters)_指定一个或多个用于在相关类型的附属脚本中访问元素的索引例如表达式`object[i]`中的`i`。尽管用于元素访问的索引可以是任意类型的但是每个变量必须包含一个用于指定每种索引类型的类型标注。_返回类型(return type)_指定被访问的元素的类型。 _变量(parameters)_指定一个或多个用于在相关类型的附属脚本中访问元素的索引例如表达式`object[i]`中的`i`。尽管用于元素访问的索引可以是任意类型的但是每个变量必须包含一个用于指定每种索引类型的类型标注。_返回类型(return type)_指定被访问的元素的类型。
@ -840,13 +785,12 @@ setter的名字和封闭的括号是可选的。如果使用了setter名称
更多关于附属脚本和附属脚本声明的例子,请参考[Subscripts](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Subscripts.html#//apple_ref/doc/uid/TP40014097-CH16-XID_393)。 更多关于附属脚本和附属脚本声明的例子,请参考[Subscripts](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Subscripts.html#//apple_ref/doc/uid/TP40014097-CH16-XID_393)。
>GRAMMAR OF A SUBSCRIPT DECLARATION > 附属脚本声明语法
> *附属脚本声明* → [*附属脚本头(Head)*](..\chapter3\05_Declarations.html#subscript_head) [*附属脚本结果(Result)*](..\chapter3\05_Declarations.html#subscript_result) [*代码块*](..\chapter3\05_Declarations.html#code_block)
>subscript-declarationsubscript-head­subscript-result­code-block­ > *附属脚本声明* → [*附属脚本头(Head)*](..\chapter3\05_Declarations.html#subscript_head) [*附属脚本结果(Result)*](..\chapter3\05_Declarations.html#subscript_result) [*getter-setter块*](..\chapter3\05_Declarations.html#getter_setter_block)
>subscript-declarationsubscript-head­subscript-result­getter-setter-block­ > *附属脚本声明* → [*附属脚本头(Head)*](..\chapter3\05_Declarations.html#subscript_head) [*附属脚本结果(Result)*](..\chapter3\05_Declarations.html#subscript_result) [*getter-setter关键字(Keyword)块*](..\chapter3\05_Declarations.html#getter_setter_keyword_block)
>subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­ > *附属脚本头(Head)* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **subscript** [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause)
>subscript-head → attributes­opt­subscript­parameter-clause­ > *附属脚本结果(Result)* → **->** [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type)
>subscript-result → ->­attributes­opt­type­
<a name="operator_declaration"></a> <a name="operator_declaration"></a>
##运算符声明(translated by 林) ##运算符声明(translated by 林)
@ -889,14 +833,13 @@ _中缀_运算符是二元运算符它可以被置于两个操作数之间
声明了一个新的运算符以后,需要声明一个跟这个运算符同名的函数来实现这个运算符。如何实现一个新的运算符,请参考[Custom Operators](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_48)。 声明了一个新的运算符以后,需要声明一个跟这个运算符同名的函数来实现这个运算符。如何实现一个新的运算符,请参考[Custom Operators](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_48)。
>GRAMMAR OF AN OPERATOR DECLARATION > 运算符声明语法
> > *运算符声明* → [*前置运算符声明*](..\chapter3\05_Declarations.html#prefix_operator_declaration) | [*后置运算符声明*](..\chapter3\05_Declarations.html#postfix_operator_declaration) | [*中置运算符声明*](..\chapter3\05_Declarations.html#infix_operator_declaration)
>operator-declaration → prefix-operator-declaration­ postfix-operator-declaration­ >infix-operator-declaration­ > *前置运算符声明* → **运算符** **prefix** [*运算符*](LexicalStructure.html#operator) **{** **}**
>prefix-operator-declaration → operator ­prefix­ operator­{­}­ > *后置运算符声明* → **运算符** **postfix** [*运算符*](LexicalStructure.html#operator) **{** **}**
>postfix-operator-declaration → operator ­postfix­ operator­{­}­ > *中置运算符声明* → **运算符** **infix** [*运算符*](LexicalStructure.html#operator) **{** [*中置运算符属性*](..\chapter3\05_Declarations.html#infix_operator_attributes) _可选_ **}**
>infix-operator-declaration → operator­infix­operator­{­infix-operator-attributes­opt­}­ > *中置运算符属性* → [*优先级子句*](..\chapter3\05_Declarations.html#precedence_clause) _可选_ [*结和性子句*](..\chapter3\05_Declarations.html#associativity_clause) _可选_
>infix-operator-attributes → precedence-clause­opt­associativity-clause­opt­ > *优先级子句***precedence** [*优先级水平*](..\chapter3\05_Declarations.html#precedence_level)
>precedence-clause → precedence­precedence-level­ > *优先级水平* → 数值 0 到 255
>precedence-level → Digit 0 through 255 > *结和性子句* → **associativity** [*结和性*](..\chapter3\05_Declarations.html#associativity)
>associativity-clause → associativity­associativity­ > *结和性***left** | **right** | **none**
>associativity → left­ right­ none

View File

@ -114,14 +114,14 @@ Interface Builder特性是Interface Builder用来与Xcode同步的声明特性
该特性用于修饰函数或方法的类型,表明该函数或方法不会返回到它的调用者中去。你也可以用它标记函数或方法的声明,表示函数或方法的相应类型,`T`,是`@noreturn T` 该特性用于修饰函数或方法的类型,表明该函数或方法不会返回到它的调用者中去。你也可以用它标记函数或方法的声明,表示函数或方法的相应类型,`T`,是`@noreturn T`
> 特性语法 > 特性语法
> attribute -> @ [attribute-name]() [attribute-argument-clause]()opt > *特色* → **@** [*特性名*](..\chapter3\06_Attributes.html#attribute_name) [*特性参数子句*](..\chapter3\06_Attributes.html#attribute_argument_clause) _可选_
> attribute-name -> [identifier]() > *特性名* → [*标识符*](LexicalStructure.html#identifier)
> attribute-argument-clause -> ( [balanced-tokens]()opt ) > *特性参数子句* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)**
> attributes -> [attribute]() [attributes]()opt > *特性(Attributes)列表* → [*特色*](..\chapter3\06_Attributes.html#attribute) [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_
> balanced-tokens -> [balanced-token]() [balanced-tokens]()opt > *平衡令牌列表* → [*平衡令牌*](..\chapter3\06_Attributes.html#balanced_token) [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_
> balanced-token -> ( [balanced-tokens]()opt ) > *平衡令牌* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)**
> balanced-token -> [ [balanced-tokens]()opt ] > *平衡令牌* → **[** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **]**
> balanced-token -> { [balanced-tokens]()opt } > *平衡令牌* → **{** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **}**
> balanced-token -> 任意标识符关键字字面量或运算符 > *平衡令牌* → **任意标识符, 关键字, 字面量或运算符**
> balanced-token -> 任意标点符号,除了(, ), [, ], {, 或 } > *平衡令牌* → **任意标点除了(, ), [, ], {, 或 }**

View File

@ -1,6 +1,6 @@
> 翻译honghaoz > 翻译honghaoz
> 校对numbbbbb > 校对numbbbbb, stanzhai
# 模式Patterns # 模式Patterns
----------------- -----------------
@ -11,7 +11,7 @@
- [标识符模式Identifier Pattern](#identifier_pattern) - [标识符模式Identifier Pattern](#identifier_pattern)
- [值绑定模式Value-Binding Pattern](#value-binding_pattern) - [值绑定模式Value-Binding Pattern](#value-binding_pattern)
- [元组模式Tuple Pattern](#tuple_pattern) - [元组模式Tuple Pattern](#tuple_pattern)
- [枚举例模式Enumeration Case Pattern](#enumeration_case_pattern) - [枚举例模式Enumeration Case Pattern](#enumeration_case_pattern)
- [类型转换模式Type-Casting Patterns](#type-casting_patterns) - [类型转换模式Type-Casting Patterns](#type-casting_patterns)
- [表达式模式Expression Pattern](#expression_pattern) - [表达式模式Expression Pattern](#expression_pattern)
@ -21,49 +21,40 @@
你可以为通配符模式wildcard pattern标识符模式identifier pattern和元组模式tuple pattern指定类型注释用来限制这种模式只匹配某种类型的值。 你可以为通配符模式wildcard pattern标识符模式identifier pattern和元组模式tuple pattern指定类型注释用来限制这种模式只匹配某种类型的值。
> 模式的语法: > 模式(Patterns) 语法
> > *模式* → [*通配符模式*](..\chapter3\07_Patterns.html#wildcard_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotation) _可选_
> pattern → wildcard-patterntype-annotationopt > *模式* → [*标识符模式*](..\chapter3\07_Patterns.html#identifier_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotati(Value Binding)on) _可选_
> > *模式* → [*值绑定模式*](..\chapter3\07_Patterns.html#value_binding_pattern)
> pattern → identifier-patterntype-annotationopt > *模式* → [*元组模式*](..\chapter3\07_Patterns.html#tuple_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotation) _可选_
> > *模式* → [*enum-case-pattern*](..\chapter3\07_Patterns.html#enum_case_pattern)
> pattern → value-binding-pattern > *模式* → [*type-casting-pattern*](..\chapter3\07_Patterns.html#type_casting_pattern)
> > *模式* → [*表达式模式*](..\chapter3\07_Patterns.html#expression_pattern)
> pattern → tuple-patterntype-annotationopt
>
> pattern → enum-case-pattern
>
> pattern → type-casting-pattern
>
> pattern → expression-pattern
<a name="wildcard_pattern"></a> <a name="wildcard_pattern"></a>
## 通配符模式Wildcard Pattern ## 通配符模式Wildcard Pattern
通配符模式匹配并忽略任何值包含一个下划线_。当你不关心被匹配的值时可以使用此模式。例如下面这段代码进行了`1...3`的循环,并忽略了每次循环的值: 通配符模式匹配并忽略任何值包含一个下划线_。当你不关心被匹配的值时可以使用此模式。例如下面这段代码进行了`1...3`的循环,并忽略了每次循环的值:
for _ in 1...3 { for _ in 1...3 {
// Do something three times. // Do something three times.
} }
> 通配符模式语法 > 通配符模式语法
> > *通配符模式* → **_**
> wildcard-pattern → _
<a name="identifier_pattern"></a> <a name="identifier_pattern"></a>
## 标识符模式Identifier Pattern ## 标识符模式Identifier Pattern
标识符模式匹配任何值,并将匹配的值和一个变量或常量绑定起来。例如,在下面的常量申明中,`someValue`是一个标识符模式,匹配了类型是`Int``42` 标识符模式匹配任何值,并将匹配的值和一个变量或常量绑定起来。例如,在下面的常量申明中,`someValue`是一个标识符模式,匹配了类型是`Int``42`
let someValue = 42 let someValue = 42
当匹配成功时,`42`被绑定(赋值)给常量`someValue` 当匹配成功时,`42`被绑定(赋值)给常量`someValue`
当一个变量或常量申明的左边是标识符模式时此时标识符模式是隐式的值绑定模式value-binding pattern 当一个变量或常量申明的左边是标识符模式时此时标识符模式是隐式的值绑定模式value-binding pattern
> 标识符模式语法 > 标识符模式语法
> > *标识符模式* → [*标识符*](LexicalStructure.html#identifier)
> identifier-pattern → identifier
<a name="value-binding_pattern"></a> <a name="value-binding_pattern"></a>
## 值绑定模式Value-Binding Pattern ## 值绑定模式Value-Binding Pattern
@ -72,19 +63,18 @@
标识符模式包含在值绑定模式中,绑定新的变量或常量到匹配的值。例如,你可以分解一个元组的元素,并把每个元素绑定到相应的标识符模式中。 标识符模式包含在值绑定模式中,绑定新的变量或常量到匹配的值。例如,你可以分解一个元组的元素,并把每个元素绑定到相应的标识符模式中。
let point = (3, 2) let point = (3, 2)
switch point { switch point {
// Bind x and y to the elements of point. // Bind x and y to the elements of point.
case let (x, y): case let (x, y):
println("The point is at (\(x), \(y)).") println("The point is at (\(x), \(y)).")
} }
// prints "The point is at (3, 2).” // prints "The point is at (3, 2).”
在上面这个例子中,`let`将元组模式`(x, y)`分配到各个标识符模式。因为这种行为,`switch`语句中`case let (x, y):``case (let x, let y):`匹配的值是一样的。 在上面这个例子中,`let`将元组模式`(x, y)`分配到各个标识符模式。因为这种行为,`switch`语句中`case let (x, y):``case (let x, let y):`匹配的值是一样的。
> 值绑定模式语法 > 值绑定(Value Binding)模式语法
> > *值绑定模式* → **var** [*模式*](..\chapter3\07_Patterns.html#pattern) | **let** [*模式*](..\chapter3\07_Patterns.html#pattern)
> value-binding-pattern → var pattern | let pattern
<a name="tuple_pattern"></a> <a name="tuple_pattern"></a>
## 元组模式Tuple Pattern ## 元组模式Tuple Pattern
@ -95,44 +85,40 @@
当元组模式被用在`for-in`语句或者变量或常量申明时,它可以包含通配符模式,标识符模式或者其他包含这两种模式的模式。例如,下面这段代码是不正确的,因为`(x, 0)`中的元素`0`是一个表达式模式: 当元组模式被用在`for-in`语句或者变量或常量申明时,它可以包含通配符模式,标识符模式或者其他包含这两种模式的模式。例如,下面这段代码是不正确的,因为`(x, 0)`中的元素`0`是一个表达式模式:
let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)] let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)]
// This code isn't valid. // This code isn't valid.
for (x, 0) in points { for (x, 0) in points {
/* ... */ /* ... */
} }
对于只包含一个元素的元组,括号是不起作用的。模式匹配那个单个元素的类型。例如,下面是等效的: 对于只包含一个元素的元组,括号是不起作用的。模式匹配那个单个元素的类型。例如,下面是等效的:
let a = 2 // a: Int = 2 let a = 2 // a: Int = 2
let (a) = 2 // a: Int = 2 let (a) = 2 // a: Int = 2
let (a): Int = 2 // a: Int = 2 let (a): Int = 2 // a: Int = 2
> 元组模式语法 > 元组模式语法
> > *元组模式* → **(** [*元组模式元素列表*](..\chapter3\07_Patterns.html#tuple_pattern_element_list) _可选_ **)**
> tuple-pattern → (tuple-pattern-element-list opt) > *元组模式元素列表* → [*元组模式元素*](..\chapter3\07_Patterns.html#tuple_pattern_element) | [*元组模式元素*](..\chapter3\07_Patterns.html#tuple_pattern_element) **,** [*元组模式元素列表*](..\chapter3\07_Patterns.html#tuple_pattern_element_list)
> > *元组模式元素* → [*模式*](..\chapter3\07_Patterns.html#pattern)
> tuple-pattern-element-list → tuple-pattern-element | tuple-pattern-element, tuple-pattern-element-list
>
> tuple-pattern-element → pattern
<a name="enumeration_case_pattern"></a> <a name="enumeration_case_pattern"></a>
## 枚举例模式Enumeration Case Pattern ## 枚举例模式Enumeration Case Pattern
枚举例模式匹配现有的枚举类型的某种例。枚举例模式仅在`switch`语句中的`case`标签中出现。 枚举例模式匹配现有的枚举类型的某种例。枚举例模式仅在`switch`语句中的`case`标签中出现。
如果你准备匹配的枚举例有任何关联的值,则相应的枚举例模式必须指定一个包含每个关联值元素的元组模式。关于使用`switch`语句来匹配包含关联值枚举例的例子,请参阅`Associated Values`. 如果你准备匹配的枚举例有任何关联的值,则相应的枚举例模式必须指定一个包含每个关联值元素的元组模式。关于使用`switch`语句来匹配包含关联值枚举例的例子,请参阅`Associated Values`.
> 枚举例模式语法 > 枚举例模式语法
> > *enum-case-pattern* → [*类型标识*](..\chapter3\03_Types.html#type_identifier) _可选_ **.** [*枚举的case名*](..\chapter3\05_Declarations.html#enum_case_name) [*元组模式*](..\chapter3\07_Patterns.html#tuple_pattern) _可选_
> enum-case-pattern → type-identifier opt . enum-case-name tuple-pattern opt
<a name="type-casting_patterns"></a> <a name="type-casting_patterns"></a>
## 类型转换模式Type-Casting Patterns ## 类型转换模式Type-Casting Patterns
有两种类型转换模式,`is`模式和`as`模式。这两种模式均只出现在`switch`语句中的`case`标签中。`is`模式和`as`模式有以下形式: 有两种类型转换模式,`is`模式和`as`模式。这两种模式均只出现在`switch`语句中的`case`标签中。`is`模式和`as`模式有以下形式:
is type is type
pattern as type pattern as type
`is`模式匹配一个值如果这个值的类型在运行时runtime`is`模式右边的指定类型(或者那个类型的子类)是一致的。`is`模式和`is`操作符一样,他们都进行类型转换,但是抛弃了返回的类型。 `is`模式匹配一个值如果这个值的类型在运行时runtime`is`模式右边的指定类型(或者那个类型的子类)是一致的。`is`模式和`is`操作符一样,他们都进行类型转换,但是抛弃了返回的类型。
@ -140,13 +126,10 @@
关于使用`switch`语句来匹配`is`模式和`as`模式值的例子,请参阅`Type Casting for Any and AnyObject` 关于使用`switch`语句来匹配`is`模式和`as`模式值的例子,请参阅`Type Casting for Any and AnyObject`
> 类型转换模式语法 > 类型转换模式语法
> > *type-casting-pattern* → [*is模式*](..\chapter3\07_Patterns.html#is_pattern) | [*as模式*](..\chapter3\07_Patterns.html#as_pattern)
> type-casting-pattern → is-pattern as-pattern > *is模式* → **is** [*类型*](..\chapter3\03_Types.html#type)
> > *as模式* → [*模式*](..\chapter3\07_Patterns.html#pattern) **as** [*类型*](..\chapter3\03_Types.html#type)
> is-pattern → istype
>
> as-pattern → patternastype
<a name="expression_pattern"></a> <a name="expression_pattern"></a>
## 表达式模式Expression Pattern ## 表达式模式Expression Pattern
@ -155,34 +138,33 @@
由表达式模式所代表的表达式用Swift标准库中的`~=`操作符与输入表达式的值进行比较。如果`~=`操作符返回`true`,则匹配成功。默认情况下,`~=`操作符使用`==`操作符来比较两个相同类型的值。它也可以匹配一个整数值与一个`Range`对象中的整数范围,正如下面这个例子所示: 由表达式模式所代表的表达式用Swift标准库中的`~=`操作符与输入表达式的值进行比较。如果`~=`操作符返回`true`,则匹配成功。默认情况下,`~=`操作符使用`==`操作符来比较两个相同类型的值。它也可以匹配一个整数值与一个`Range`对象中的整数范围,正如下面这个例子所示:
let point = (1, 2) let point = (1, 2)
switch point { switch point {
case (0, 0): case (0, 0):
println("(0, 0) is at the origin.") println("(0, 0) is at the origin.")
case (-2...2, -2...2): case (-2...2, -2...2):
println("(\(point.0), \(point.1)) is near the origin.") println("(\(point.0), \(point.1)) is near the origin.")
default: default:
println("The point is at (\(point.0), \(point.1)).") println("The point is at (\(point.0), \(point.1)).")
} }
// prints "(1, 2) is near the origin.” // prints "(1, 2) is near the origin.”
你可以重载`~=`操作符来提供自定义的表达式行为。例如,你可以重写上面的例子,以实现用字符串表达的点来比较`point`表达式。 你可以重载`~=`操作符来提供自定义的表达式行为。例如,你可以重写上面的例子,以实现用字符串表达的点来比较`point`表达式。
// Overload the ~= operator to match a string with an integer // Overload the ~= operator to match a string with an integer
func ~=(pattern: String, value: Int) -> Bool { func ~=(pattern: String, value: Int) -> Bool {
return pattern == "\(value)" return pattern == "\(value)"
} }
switch point { switch point {
case ("0", "0"): case ("0", "0"):
println("(0, 0) is at the origin.") println("(0, 0) is at the origin.")
case ("-2...2", "-2...2"): case ("-2...2", "-2...2"):
println("(\(point.0), \(point.1)) is near the origin.") println("(\(point.0), \(point.1)) is near the origin.")
default: default:
println("The point is at (\(point.0), \(point.1)).") println("The point is at (\(point.0), \(point.1)).")
} }
// prints "(1, 2) is near the origin.” // prints "(1, 2) is near the origin.”
> 表达式模式语法 > 表达式模式语法
> > *表达式模式* → [*表达式*](..\chapter3\04_Expressions.html#expression)
> expression-pattern → expression

View File

@ -1,4 +1,4 @@
> 翻译:StanZhai > 翻译:stanzhai
> 校对xielingwang > 校对xielingwang
@ -417,8 +417,8 @@ _________________
> *平衡令牌* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)** > *平衡令牌* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)**
> *平衡令牌* → **[** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **]** > *平衡令牌* → **[** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **]**
> *平衡令牌* → **{** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **}** > *平衡令牌* → **{** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **}**
> *平衡令牌* → 任意标识符, 关键字, 字面量或运算符 > *平衡令牌* → **任意标识符, 关键字, 字面量或运算符**
> *平衡令牌* → 任意除了(-, )=, [-, ]-, {- 或 }- > *平衡令牌* → **任意标点除了(, ), [, ], {, 或 }**
<a name="expressions"></a> <a name="expressions"></a>
## 表达式 ## 表达式