| Character | +D U+0044 |
+ o U+006F |
+ g U+0067 |
+ ‼ U+1F436 |
+ 🐶 U+1F436 |
+ |||||
| UTF-8 Code Unit |
+ 68 | +111 | +103 | +226 | +128 | +188 | +240 | +159 | +144 | +182 | +
| Position | +0 | +1 | +2 | +3 | +4 | +5 | +6 | +7 | +8 | +9 | +
| Character | +D U+0044 |
+ o U+006F |
+ g U+0067 |
+ ‼ U+1F436 |
+ 🐶 U+1F436 |
+ |
| UTF-16 Code Unit |
+ 68 | +111 | +103 | +8252 | +55357 | +56374 | +
| Position | +0 | +1 | +2 | +3 | +4 | +5 | +
| Character | +D U+0044 |
+ o U+006F |
+ g U+0067 |
+ ‼ U+1F436 |
+ 🐶 U+1F436 |
+
| UTF-16 Code Unit |
+ 68 | +111 | +103 | +8252 | +128054 | +
| Position | +0 | +1 | +2 | +3 | +4 | +
@@ -128,28 +128,28 @@ default:
对于库存跟踪系统来说,能够把 UPC-A 码作为三个整型值的元组,和把 QR 码作为一个任何长度的字符串存储起来是方便的。
-在 Swift 中,用来定义两种商品条码的枚举是这样子的:
+在 Swift 中,使用如下方式定义两种商品条码的枚举:
```swift
enum Barcode {
- case UPCA(Int, Int, Int)
+ case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
```
以上代码可以这么理解:
-“定义一个名为`Barcode`的枚举类型,它可以是`UPCA`的一个相关值(`Int`,`Int`,`Int`),或者`QRCode`的一个字符串类型(`String`)相关值。”
+“定义一个名为`Barcode`的枚举类型,它可以是`UPCA`的一个相关值(`Int`,`Int`,`Int`,`Int`),或者是`QRCode`的一个字符串类型(`String`)相关值。”
这个定义不提供任何`Int`或`String`的实际值,它只是定义了,当`Barcode`常量和变量等于`Barcode.UPCA`或`Barcode.QRCode`时,相关值的类型。
然后可以使用任何一种条码类型创建新的条码,如:
```swift
-var productBarcode = Barcode.UPCA(8, 85909_51226, 3)
+var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
```
-以上例子创建了一个名为`productBarcode`的新变量,并且赋给它一个`Barcode.UPCA`的相关元组值`(8, 8590951226, 3)`。提供的“标识符”值在整数字中有一个下划线,使其便于阅读条形码。
+以上例子创建了一个名为`productBarcode`的变量,并且赋给它一个`Barcode.UPCA`的相关元组值`(8, 85909, 51226, 3)`。
同一个商品可以被分配给一个不同类型的条形码,如:
@@ -163,32 +163,32 @@ productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
```swift
switch productBarcode {
-case .UPCA(let numberSystem, let identifier, let check):
- println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
+case .UPCA(let numberSystem, let manufacturer, let product, let check):
+ print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case .QRCode(let productCode):
- println("QR code with value of \(productCode).")
+ print("QR code: \(productCode).")
}
-// 输出 "QR code with value of ABCDEFGHIJKLMNOP.”
+// 输出 "QR code: ABCDEFGHIJKLMNOP."
```
如果一个枚举成员的所有相关值被提取为常量,或者它们全部被提取为变量,为了简洁,你可以只放置一个`var`或者`let`标注在成员名称前:
```swift
switch productBarcode {
-case let .UPCA(numberSystem, identifier, check):
- println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
+case let .UPCA(numberSystem, manufacturer, product, check):
+ print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case let .QRCode(productCode):
- println("QR code with value of \(productCode).")
+ print("QR code: \(productCode).")
}
-// 输出 "QR code with value of ABCDEFGHIJKLMNOP."
+// 输出 "QR code: ABCDEFGHIJKLMNOP."
```
## 原始值(Raw Values)
-在[Associated Values](#raw_values)小节的条形码例子中演示了一个枚举的成员如何声明它们存储不同类型的相关值。作为相关值的替代,枚举成员可以被默认值(称为原始值)预先填充,其中这些原始值具有相同的类型。
+在[Associated Values](#raw_values)小节的条形码例子中演示了一个枚举的成员如何声明它们存储不同类型的相关值。作为相关值的另一种选择,枚举成员可以被默认值(称为原始值)赋值,其中这些原始值具有相同的类型。
-这里是一个枚举成员存储原始 ASCII 值的例子:
+这里是一个枚举成员存储 ASCII 码的例子:
```swift
enum ASCIIControlCharacter: Character {
@@ -198,11 +198,11 @@ enum ASCIIControlCharacter: Character {
}
```
-在这里,称为`ASCIIControlCharacter`的枚举的原始值类型被定义为字符型`Character`,并被设置了一些比较常见的 ASCII 控制字符。字符值的描述请详见字符串和字符[`Strings and Characters`](03_Strings_and_Characters.html)部分。
+在这里,`ASCIIControlCharacter`的枚举类型的原始值类型被定义为字符型`Character`,并被设置了一些比较常见的 ASCII 控制字符。字符值的描述请详见字符串和字符[`Strings and Characters`](03_Strings_and_Characters.html)部分。
-注意,原始值和相关值是不相同的。当你开始在你的代码中定义枚举的时候原始值是被预先填充的值,像上述三个 ASCII 码。对于一个特定的枚举成员,它的原始值始终是相同的。相关值是当你在创建一个基于枚举成员的新常量或变量时才会被设置,并且每次当你这么做得时候,它的值可以是不同的。
+注意,原始值和相关值是不相同的。原始值是当你开始定义枚举的时候被预先赋予的值,像上述三个 ASCII 码。对于一个特定的枚举成员,它的原始值始终是相同的。相关值在你在创建一个基于枚举成员的常量或变量时才会被设置,并且每次当你创建的时候,它的值可以是不同的。
-原始值可以是字符串,字符,或者任何整型值或浮点型值。每个原始值在它的枚举声明中必须是唯一的。当整型值被用于原始值,如果其他枚举成员没有值时,它们会自动递增。
+原始值可以是字符串,字符,或者任何整型值或浮点型值。每个原始值在它的枚举声明中必须是唯一的。当使用整型值作为原始值时,如果其他枚举成员没有值,它们会自动递增。
下面的枚举是对之前`Planet`这个枚举的一个细化,利用原始整型值来表示每个 planet 在太阳系中的顺序:
@@ -212,7 +212,7 @@ enum Planet: Int {
}
```
-自动递增意味着`Planet.Venus`的原始值是`2`,依次类推。
+自动递增意味着`Planet.Venus`的原始值是`2`,以此类推。
使用枚举成员的`rawValue`属性可以访问该枚举成员的原始值:
@@ -220,15 +220,22 @@ enum Planet: Int {
let earthsOrder = Planet.Earth.rawValue
// earthsOrder is 3
```
+### 使用原始值来初始化(Initializing from a Raw Value)
-通过参数为`rawValue`构造函数创建特定原始值的枚举。这个例子通过原始值`7`识别`Uranus`:
+如果你使用原始值的方式创建一个枚举类型,这个枚举将自动获得一个包含原始值参数(参数名为rawValue)的构造器并返回相应的枚举类型或者nil。你可以使用这个构造器来创建新的枚举成员。
+
+下面这个例子通过原始值`7`创建了`Uranus`枚举类型:
```swift
let possiblePlanet = Planet(rawValue: 7)
// possiblePlanet is of type Planet? and equals Planet.Uranus
```
-然而,并非所有可能的`Int`值都可以找到一个匹配的行星。正因为如此,构造函数可以返回一个***可选***的枚举成员。在上面的例子中,`possiblePlanet`是`Planet?`类型,或“可选的`Planet`”。
+然而,并非所有可能的`Int`值都可以找到一个匹配的行星。正因为如此,构造函数可以返回一个*可选*的枚举成员。在上面的例子中,`possiblePlanet`是`Planet?`类型,或称为“可选的`Planet`”。
+
+> 注意:
+> 使用原始值构造器是可失败构造器,因为并不是所有的原始值都会返回一个对应的枚举成员。欲了解更多相关信息,请参见[可失败构造器(Failable Initializers)](TODO)
+
如果你试图寻找一个位置为9的行星,通过参数为`rawValue`构造函数返回的可选`Planet`值将是`nil`:
@@ -237,15 +244,14 @@ let positionToFind = 9
if let somePlanet = Planet(rawValue: positionToFind) {
switch somePlanet {
case .Earth:
- println("Mostly harmless")
+ print("Mostly harmless")
default:
- println("Not a safe place for humans")
+ print("Not a safe place for humans")
}
} else {
- println("There isn't a planet at position \(positionToFind)")
+ print("There isn't a planet at position \(positionToFind)")
}
// 输出 "There isn't a planet at position 9
```
-这个范例使用可选绑定(optional binding),通过原始值`9`试图访问一个行星。`if let somePlanet = Planet(rawValue: 9)`语句获得一个可选`Planet`,如果可选`Planet`可以被获得,把`somePlanet`设置成该可选`Planet`的内容。在这个范例中,无法检索到位置为`9`的行星,所以`else`分支被执行。
-
+这个范例使用可选绑定(optional binding),通过原始值`9`试图取得一个行星的引用。`if let somePlanet = Planet(rawValue: 9)`语句获得一个可选`Planet`,如果可选`Planet`可以被获得,把`somePlanet`设置成该可选`Planet`的内容。在这个范例中,无法检索到位置为`9`的行星,所以`else`分支被执行。
diff --git a/source/chapter2/10_Properties.md b/source/chapter2/10_Properties.md
index bf305032..3ee6921e 100755
--- a/source/chapter2/10_Properties.md
+++ b/source/chapter2/10_Properties.md
@@ -1,5 +1,5 @@
> 翻译:[shinyzhu](https://github.com/shinyzhu)
-> 校对:[pp-prog](https://github.com/pp-prog)
+> 校对:[pp-prog](https://github.com/pp-prog) [yangsiy](https://github.com/yangsiy)
# 属性 (Properties)
---
@@ -12,16 +12,16 @@
- [全局变量和局部变量(Global and Local Variables)](#global_and_local_variables)
- [类型属性(Type Properties)](#type_properties)
-**属性**将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,计算属性计算(而不是存储)一个值。计算属性可以用于类、结构体和枚举里,存储属性只能用于类和结构体。
+*属性*将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,而计算属性计算(不是存储)一个值。计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体。
-存储属性和计算属性通常用于特定类型的实例,但是,属性也可以直接用于类型本身,这种属性称为类型属性。
+存储属性和计算属性通常与特定类型的实例关联。但是,属性也可以直接作用于类型本身,这种属性称为类型属性。
-另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己写的存储属性上,也可以添加到从父类继承的属性上。
+另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己定义的存储属性上,也可以添加到从父类继承的属性上。
## 存储属性
-简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量,存储属性可以是*变量存储属性*(用关键字`var`定义),也可以是*常量存储属性*(用关键字`let`定义)。
+简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。存储属性可以是*变量存储属性*(用关键字`var`定义),也可以是*常量存储属性*(用关键字`let`定义)。
可以在定义存储属性的时候指定默认值,请参考[构造过程](../chapter2/14_Initialization.html)一章的[默认属性值](../chapter2/14_Initialization.html#default_property_values)一节。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值,请参考[构造过程](../chapter2/14_Initialization.html)一章的[在初始化阶段修改常量存储属性](../chapter2/14_Initialization.html#modifying_constant_properties_during_initialization)一节。
@@ -38,12 +38,12 @@ rangeOfThreeItems.firstValue = 6
// 该区间现在表示整数6,7,8
```
-`FixedLengthRange`的实例包含一个名为`firstValue`的变量存储属性和一个名为`length`的常量存储属性。在上面的例子中,`length`在创建实例的时候被赋值,因为它是一个常量存储属性,所以之后无法修改它的值。
+`FixedLengthRange`的实例包含一个名为`firstValue`的变量存储属性和一个名为`length`的常量存储属性。在上面的例子中,`length`在创建实例的时候被初始化,因为它是一个常量存储属性,所以之后无法修改它的值。
-### 常量和存储属性
+### 常量结构体的存储属性
-如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性:
+如果创建了一个结构体的实例并将其赋值给一个常量,则无法修改该实例的任何属性,即使定义了变量存储属性:
```swift
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
@@ -52,11 +52,11 @@ rangeOfFourItems.firstValue = 6
// 尽管 firstValue 是个变量属性,这里还是会报错
```
-因为`rangeOfFourItems`声明成了常量(用`let`关键字),即使`firstValue`是一个变量属性,也无法再修改它了。
+因为`rangeOfFourItems`被声明成了常量(用`let`关键字),即使`firstValue`是一个变量属性,也无法再修改它了。
这种行为是由于结构体(struct)属于*值类型*。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。
-属于*引用类型*的类(class)则不一样,把一个引用类型的实例赋给一个常量后,仍然可以修改实例的变量属性。
+属于*引用类型*的类(class)则不一样。把一个引用类型的实例赋给一个常量后,仍然可以修改该实例的变量属性。
### 延迟存储属性
@@ -64,11 +64,11 @@ rangeOfFourItems.firstValue = 6
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用`lazy`来标示一个延迟存储属性。
> 注意:
-> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
+> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
-延迟属性很有用,当属性的值依赖于在实例的构造过程结束前无法知道具体值的外部因素时,或者当属性的值需要复杂或大量计算时,可以只在需要的时候来计算它。
+延迟属性很有用,当属性的值依赖于在实例的构造过程结束后才会知道具体值的外部因素时,或者当获得属性的初始值需要复杂或大量计算时,可以只在需要的时候计算它。
-下面的例子使用了延迟存储属性来避免复杂类的不必要的初始化。例子中定义了`DataImporter`和`DataManager`两个类,下面是部分代码:
+下面的例子使用了延迟存储属性来避免复杂类中不必要的初始化。例子中定义了`DataImporter`和`DataManager`两个类,下面是部分代码:
```swift
class DataImporter {
@@ -94,30 +94,32 @@ manager.data.append("Some more data")
`DataManager`类包含一个名为`data`的存储属性,初始值是一个空的字符串(`String`)数组。虽然没有写出全部代码,`DataManager`类的目的是管理和提供对这个字符串数组的访问。
-`DataManager`的一个功能是从文件导入数据,该功能由`DataImporter`类提供,`DataImporter`需要消耗不少时间完成初始化:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。
+`DataManager`的一个功能是从文件导入数据。该功能由`DataImporter`类提供,`DataImporter`完成初始化需要消耗不少时间:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。
-`DataManager`也可能不从文件中导入数据。所以当`DataManager`的实例被创建时,没必要创建一个`DataImporter`的实例,更明智的是当用到`DataImporter`的时候才去创建它。
+`DataManager`也可能不从文件中导入数据就完成了管理数据的功能。所以当`DataManager`的实例被创建时,没必要创建一个`DataImporter`的实例,更明智的是当第一次用到`DataImporter`的时候才去创建它。
由于使用了`lazy`,`importer`属性只有在第一次被访问的时候才被创建。比如访问它的属性`fileName`时:
```swift
-println(manager.importer.fileName)
+print(manager.importer.fileName)
// DataImporter 实例的 importer 属性现在被创建了
// 输出 "data.txt”
-```
+```
+
+> 注意:
+> 如果一个被标记为`lazy`的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。
### 存储属性和实例变量
-如果您有过 Objective-C 经验,应该知道Objective-C为类实例存储值和引用提供两种方法。对于属性来说,也可以使用实例变量作为属性值的后端存储。
+如果您有过 Objective-C 经验,应该知道 Objective-C 为类实例存储值和引用提供两种方法。对于属性来说,也可以使用实例变量作为属性值的后端存储。
-Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。
-一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。
+Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。
## 计算属性
-除存储属性外,类、结构体和枚举可以定义*计算属性*,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。
+除存储属性外,类、结构体和枚举可以定义*计算属性*。计算属性不直接存储值,而是提供一个 getter 和一个可选的 setter,来间接获取和设置其他属性或变量的值。
```swift
struct Point {
@@ -130,38 +132,38 @@ struct Rect {
var origin = Point()
var size = Size()
var center: Point {
- get {
- let centerX = origin.x + (size.width / 2)
- let centerY = origin.y + (size.height / 2)
- return Point(x: centerX, y: centerY)
- }
- set(newCenter) {
- origin.x = newCenter.x - (size.width / 2)
- origin.y = newCenter.y - (size.height / 2)
- }
+ get {
+ let centerX = origin.x + (size.width / 2)
+ let centerY = origin.y + (size.height / 2)
+ return Point(x: centerX, y: centerY)
+ }
+ set(newCenter) {
+ origin.x = newCenter.x - (size.width / 2)
+ origin.y = newCenter.y - (size.height / 2)
+ }
}
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
-println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
+print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// 输出 "square.origin is now at (10.0, 10.0)”
```
-这个例子定义了 3 个几何形状的结构体:
+这个例子定义了 3 个结构体来描述几何形状:
- `Point`封装了一个`(x, y)`的坐标
-- `Size`封装了一个`width`和`height`
+- `Size`封装了一个`width`和一个`height`
- `Rect`表示一个有原点和尺寸的矩形
-`Rect`也提供了一个名为`center`的计算属性。一个矩形的中心点可以从原点和尺寸来算出,所以不需要将它以显式声明的`Point`来保存。`Rect`的计算属性`center`提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。
+`Rect`也提供了一个名为`center`的计算属性。一个矩形的中心点可以从原点(`origin`)和尺寸(`size`)算出,所以不需要将它以显式声明的`Point`来保存。`Rect`的计算属性`center`提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。
-例子中接下来创建了一个名为`square`的`Rect`实例,初始值原点是`(0, 0)`,宽度高度都是`10`。如图所示蓝色正方形。
+上述例子中创建了一个名为`square`的`Rect`实例,初始值原点是`(0, 0)`,宽度高度都是`10`。如下图中蓝色正方形所示。
-`square`的`center`属性可以通过点运算符(`square.center`)来访问,这会调用 getter 来获取属性的值。跟直接返回已经存在的值不同,getter 实际上通过计算然后返回一个新的`Point`来表示`square`的中心点。如代码所示,它正确返回了中心点`(5, 5)`。
+`square`的`center`属性可以通过点运算符(`square.center`)来访问,这会调用该属性的 getter 来获取它的值。跟直接返回已经存在的值不同,getter 实际上通过计算然后返回一个新的`Point`来表示`square`的中心点。如代码所示,它正确返回了中心点`(5, 5)`。
-`center`属性之后被设置了一个新的值`(15, 15)`,表示向右上方移动正方形到如图所示橙色正方形的位置。设置属性`center`的值会调用 setter 来修改属性`origin`的`x`和`y`的值,从而实现移动正方形到新的位置。
+`center`属性之后被设置了一个新的值`(15, 15)`,表示向右上方移动正方形到如下图橙色正方形所示的位置。设置属性`center`的值会调用它的 setter 来修改属性`origin`的`x`和`y`的值,从而实现移动正方形到新的位置。
@@ -175,15 +177,15 @@ struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
- get {
- let centerX = origin.x + (size.width / 2)
- let centerY = origin.y + (size.height / 2)
- return Point(x: centerX, y: centerY)
- }
- set {
- origin.x = newValue.x - (size.width / 2)
- origin.y = newValue.y - (size.height / 2)
- }
+ get {
+ let centerX = origin.x + (size.width / 2)
+ let centerY = origin.y + (size.height / 2)
+ return Point(x: centerX, y: centerY)
+ }
+ set {
+ origin.x = newValue.x - (size.width / 2)
+ origin.y = newValue.y - (size.height / 2)
+ }
}
}
```
@@ -193,26 +195,24 @@ struct AlternativeRect {
只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。
-> 注意:
->
+> 注意:
> 必须使用`var`关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。
-
只读计算属性的声明可以去掉`get`关键字和花括号:
```swift
struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
- return width * height * depth
+ return width * height * depth
}
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
-println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
+print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// 输出 "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`提供一个只读计算属性来让外部用户直接获取体积是很有用的。
## 属性观察器
@@ -222,34 +222,34 @@ println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。属性重载请参考[继承](chapter/13_Inheritance.html)一章的[重载](chapter/13_Inheritance.html#overriding)。
> 注意:
-> 不需要为无法重载的计算属性添加属性观察器,因为可以通过 setter 直接监控和响应值的变化。
+> 不需要为非重载的计算属性添加属性观察器,因为可以通过它的 setter 直接监控和响应值的变化。
可以为属性添加如下的一个或全部观察器:
-- `willSet`在设置新的值之前调用
+- `willSet`在新的值被设置之前调用
- `didSet`在新的值被设置之后立即调用
-`willSet`观察器会将新的属性值作为固定参数传入,在`willSet`的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称`newValue`表示。
+`willSet`观察器会将新的属性值作为常量参数传入,在`willSet`的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称`newValue`表示。
类似地,`didSet`观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名`oldValue`。
-> 注意:
->
-> `willSet`和`didSet`观察器在属性初始化过程中不会被调用,它们只会当属性的值在初始化之外的地方被设置时被调用。
+> 注意:
+> 父类的属性在子类的构造器中被赋值时,它在父类中的`willSet`和`didSet`观察器会被调用。
+> 有关构造器代理的更多信息,请参考[值类型的构造器代理](chapter/14_Initialization.html#initializer_delegation_for_value_types)和[构造器链](chapter/14_Initialization.html#initialization_chain)。
-这里是一个`willSet`和`didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数,可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。
+这里是一个`willSet`和`didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数。这个类可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。
```swift
class StepCounter {
var totalSteps: Int = 0 {
- willSet(newTotalSteps) {
- println("About to set totalSteps to \(newTotalSteps)")
- }
- didSet {
- if totalSteps > oldValue {
- println("Added \(totalSteps - oldValue) steps")
+ willSet(newTotalSteps) {
+ print("About to set totalSteps to \(newTotalSteps)")
+ }
+ didSet {
+ if totalSteps > oldValue {
+ print("Added \(totalSteps - oldValue) steps")
+ }
}
- }
}
}
let stepCounter = StepCounter()
@@ -270,19 +270,19 @@ stepCounter.totalSteps = 896
例子中的`willSet`观察器将表示新值的参数自定义为`newTotalSteps`,这个观察器只是简单的将新的值输出。
-`didSet`观察器在`totalSteps`的值改变后被调用,它把新的值和旧的值进行对比,如果总的步数增加了,就输出一个消息表示增加了多少步。`didSet`没有提供自定义名称,所以默认值`oldValue`表示旧值的参数名。
+`didSet`观察器在`totalSteps`的值改变后被调用,它把新的值和旧的值进行对比,如果总的步数增加了,就输出一个消息表示增加了多少步。`didSet`没有为旧的值提供自定义名称,所以默认值`oldValue`表示旧值的参数名。
> 注意:
-> 如果在`didSet`观察器里为属性赋值,这个值会替换观察器之前设置的值。
+> 如果在一个属性的`didSet`观察器里为它赋值,这个值会替换该观察器之前设置的值。
##全局变量和局部变量
-计算属性和属性观察器所描述的模式也可以用于*全局变量*和*局部变量*,全局变量是在函数、方法、闭包或任何类型之外定义的变量,局部变量是在函数、方法或闭包内部定义的变量。
+计算属性和属性观察器所描述的模式也可以用于*全局变量*和*局部变量*。全局变量是在函数、方法、闭包或任何类型之外定义的变量。局部变量是在函数、方法或闭包内部定义的变量。
前面章节提到的全局或局部变量都属于存储型变量,跟存储属性类似,它提供特定类型的存储空间,并允许读取和写入。
-另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器,计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。
+另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器。计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。
> 注意:
> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`lazy`特性。
@@ -297,9 +297,7 @@ stepCounter.totalSteps = 896
类型属性用于定义特定类型所有实例共享的数据,比如所有实例都能用的一个常量(就像 C 语言中的静态常量),或者所有实例都能访问的一个变量(就像 C 语言中的静态变量)。
-对于值类型(指结构体和枚举)可以定义存储型和计算型类型属性,对于类(class)则只能定义计算型类型属性。
-
-值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样定义成变量属性。
+值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样只能定义成变量属性。
> 注意:
> 跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。
@@ -307,26 +305,30 @@ stepCounter.totalSteps = 896
###类型属性语法
-在 C 或 Objective-C 中,静态常量和静态变量的定义是通过特定类型加上`global`关键字。在 Swift 编程语言中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。
+在 C 或 Objective-C 中,与某个类型关联的静态常量和静态变量,是作为全局(*global*)静态变量定义的。但是在 Swift 编程语言中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。
-使用关键字`static`来定义值类型的类型属性,关键字`class`来为类(class)定义类型属性。下面的例子演示了存储型和计算型类型属性的语法:
+使用关键字`static`来定义类型属性。在为类(class)定义计算型类型属性时,可以使用关键字`class`来支持子类对父类的实现进行重写。下面的例子演示了存储型和计算型类型属性的语法:
```swift
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
- // 这里返回一个 Int 值
+ return 1
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
- // 这里返回一个 Int 值
+ return 6
}
}
-class SomeClass {
- class var computedTypeProperty: Int {
- // 这里返回一个 Int 值
+class SomeClass {
+ static var storedTypeProperty = "Some value."
+ static var computedTypeProperty: Int {
+ return 27
+ }
+ class var overrideableComputedTypeProperty: Int {
+ return 107
}
}
```
@@ -337,17 +339,18 @@ class SomeClass {
###获取和设置类型属性的值
-跟实例的属性一样,类型属性的访问也是通过点运算符来进行,但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如:
+跟实例的属性一样,类型属性的访问也是通过点运算符来进行。但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如:
-```swift
-println(SomeClass.computedTypeProperty)
-// 输出 "42"
-
-println(SomeStructure.storedTypeProperty)
-// 输出 "Some value."
+```swift
+print(SomeStructure.storedTypeProperty)
+// 输出 "Some value."
SomeStructure.storedTypeProperty = "Another value."
-println(SomeStructure.storedTypeProperty)
-// 输出 "Another value.”
+print(SomeStructure.storedTypeProperty)
+// 输出 "Another value.”
+print(SomeEnumeration.computedTypeProperty)
+// 输出 "6"
+print(SomeClass.computedTypeProperty)
+// 输出 "27"
```
下面的例子定义了一个结构体,使用两个存储型类型属性来表示多个声道的声音电平值,每个声道有一个 0 到 10 之间的整数表示声音电平值。
@@ -356,23 +359,23 @@ println(SomeStructure.storedTypeProperty)
-上面所描述的声道模型使用`AudioChannel`结构体来表示:
+上面所描述的声道模型使用`AudioChannel`结构体的实例来表示:
```swift
struct AudioChannel {
static let thresholdLevel = 10
static var maxInputLevelForAllChannels = 0
var currentLevel: Int = 0 {
- didSet {
- if currentLevel > AudioChannel.thresholdLevel {
- // 将新电平值设置为阀值
- currentLevel = AudioChannel.thresholdLevel
+ didSet {
+ if currentLevel > AudioChannel.thresholdLevel {
+ // 将新电平值设置为阀值
+ currentLevel = AudioChannel.thresholdLevel
+ }
+ if currentLevel > AudioChannel.maxInputLevelForAllChannels {
+ // 存储当前电平值作为新的最大输入电平
+ AudioChannel.maxInputLevelForAllChannels = currentLevel
+ }
}
- if currentLevel > AudioChannel.maxInputLevelForAllChannels {
- // 存储当前电平值作为新的最大输入电平
- AudioChannel.maxInputLevelForAllChannels = currentLevel
- }
- }
}
}
```
@@ -383,10 +386,10 @@ struct AudioChannel {
`AudioChannel`也定义了一个名为`currentLevel`的实例存储属性,表示当前声道现在的电平值,取值为 0 到 10。
-属性`currentLevel`包含`didSet`属性观察器来检查每次新设置后的属性值,有如下两个检查:
+属性`currentLevel`包含`didSet`属性观察器来检查每次新设置后的属性值,它有如下两个检查:
- 如果`currentLevel`的新值大于允许的阈值`thresholdLevel`,属性观察器将`currentLevel`的值限定为阈值`thresholdLevel`。
-- 如果修正后的`currentLevel`值大于任何之前任意`AudioChannel`实例中的值,属性观察器将新值保存在静态属性`maxInputLevelForAllChannels`中。
+- 如果前一个修正后的`currentLevel`值大于任何之前任意`AudioChannel`实例中的值,属性观察器将新值保存在静态类型属性`maxInputLevelForAllChannels`中。
> 注意:
> 在第一个检查过程中,`didSet`属性观察器将`currentLevel`设置成了不同的值,但这时不会再次调用属性观察器。
@@ -402,9 +405,9 @@ var rightChannel = AudioChannel()
```swift
leftChannel.currentLevel = 7
-println(leftChannel.currentLevel)
+print(leftChannel.currentLevel)
// 输出 "7"
-println(AudioChannel.maxInputLevelForAllChannels)
+print(AudioChannel.maxInputLevelForAllChannels)
// 输出 "7"
```
@@ -412,8 +415,8 @@ println(AudioChannel.maxInputLevelForAllChannels)
```swift
rightChannel.currentLevel = 11
-println(rightChannel.currentLevel)
+print(rightChannel.currentLevel)
// 输出 "10"
-println(AudioChannel.maxInputLevelForAllChannels)
+print(AudioChannel.maxInputLevelForAllChannels)
// 输出 "10"
```
diff --git a/source/chapter2/12_Subscripts.md b/source/chapter2/12_Subscripts.md
index 7bef609e..d9e4db4e 100755
--- a/source/chapter2/12_Subscripts.md
+++ b/source/chapter2/12_Subscripts.md
@@ -11,9 +11,9 @@
- [下标脚本用法](#subscript_usage)
- [下标脚本选项](#subscript_options)
-*下标脚本* 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问对象、集合或序列的快捷方式,不需要再调用实例的特定的赋值和访问方法。举例来说,用下标脚本访问一个数组(Array)实例中的元素可以这样写 `someArray[index]` ,访问字典(Dictionary)实例中的元素可以这样写 `someDictionary[key]`。
+*下标脚本* 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问集合(collection),列表(list)或序列(sequence的快捷方式,使用下标脚本的索引设置和获取值,不需要再调用实例的特定的赋值和访问方法。举例来说,用下标脚本访问一个数组(Array)实例中的元素可以这样写 `someArray[index]` ,访问字典(Dictionary)实例中的元素可以这样写 `someDictionary[key]`。
-对于同一个目标可以定义多个下标脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。
+对于同一个目标可以定义多个下标脚本,通过索引值类型的不同来进行重载,下标脚本不限于单个纬度,你可以定义多个入参的下标脚本满足自定义类型的需求。
> 译者:这里附属脚本重载在本小节中原文并没有任何演示
@@ -63,7 +63,7 @@ println("3的6倍是\(threeTimesTable[6])")
你可以通过下标脚本来得到结果,比如`threeTimesTable[6]`。这条语句访问了`threeTimesTable`的第六个元素,返回`6`的`3`倍即`18`。
>注意:
-> `TimesTable`例子是基于一个固定的数学公式。它并不适合开放写权限来对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么附属脚本只定义为只读的原因。
+> `TimesTable`例子是基于一个固定的数学公式。它并不适合对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么附属脚本只定义为只读的原因。
## 下标脚本用法
@@ -77,7 +77,7 @@ var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
```
-上例定义一个名为`numberOfLegs`的变量并用一个字典字面量初始化出了包含三对键值的字典实例。`numberOfLegs`的字典存放值类型推断为`Dictionarysome text
`"或者"``"。 +默认情况下,闭包赋值给了`asHTML`属性,这个闭包返回一个代表 HTML 标签的字符串。如果`text`值存在,该标签就包含可选值`text`;如果`text`不存在,该标签就不包含文本。对于段落元素,根据`text`是`"some text"`还是`nil`,闭包会返回"`some text
`"或者"``"。 可以像实例方法那样去命名、使用`asHTML`属性。然而,由于`asHTML`是闭包而不是实例方法,如果你想改变特定元素的 HTML 处理的话,可以用自定义的闭包来取代默认值。 @@ -440,7 +445,7 @@ class HTMLElement { ```swift var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") -println(paragraph!.asHTML()) +print(paragraph!.asHTML()) // prints"hello, world" ``` @@ -470,38 +475,38 @@ paragraph = nil 在定义闭包时同时定义捕获列表作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的循环强引用。捕获列表定义了闭包体内捕获一个或者多个引用类型的规则。跟解决两个类实例间的循环强引用一样,声明每个捕获的引用为弱引用或无主引用,而不是强引用。应当根据代码关系来决定使用弱引用还是无主引用。 >注意: -Swift 有如下要求:只要在闭包内使用`self`的成员,就要用`self.someProperty`或者`self.someMethod`(而不只是`someProperty`或`someMethod`)。这提醒你可能会不小心就捕获了`self`。 +Swift 有如下要求:只要在闭包内使用`self`的成员,就要用`self.someProperty`或者`self.someMethod`(而不只是`someProperty`或`someMethod`)。这提醒你可能会一不小心就捕获了`self`。 -###定义捕获列表 +###定义捕获列表 -捕获列表中的每个元素都是由`weak`或者`unowned`关键字和实例的引用(如`self`或`someInstance`)成对组成。每一对都在方括号中,通过逗号分开。 +捕获列表中的每一项都由一对元素组成,一个元素是`weak`或`unowned`关键字,另一个元素是类实例的引用(如`self`)或初始化过的变量(如`delegate = self.delegate!`)。这些项在方括号中用逗号分开。 -捕获列表放置在闭包参数列表和返回类型之前: +如果闭包有参数列表和返回类型,把捕获列表放在它们前面: ```swift lazy var someClosure: (Int, String) -> String = { - [unowned self] (index: Int, stringToProcess: String) -> String in + [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in // closure body goes here } ``` -如果闭包没有指定参数列表或者返回类型,则可以通过上下文推断,那么可以捕获列表放在闭包开始的地方,跟着是关键字`in`: +如果闭包没有指明参数列表或者返回类型,即它们会通过上下文推断,那么可以把捕获列表和关键字`in`放在闭包最开始的地方: ```swift -lazy var someClosure: () -> String = { - [unowned self] in +lazy var someClosure: Void -> String = { + [unowned self, weak delegate = self.delegate!] in // closure body goes here } ``` ###弱引用和无主引用 -当闭包和捕获的实例总是互相引用时并且总是同时销毁时,将闭包内的捕获定义为无主引用。 +在闭包和捕获的实例总是互相引用时并且总是同时销毁时,将闭包内的捕获定义为无主引用。 -相反的,当捕获引用有时可能会是`nil`时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为`nil`。这使我们可以在闭包内检查它们是否存在。 +相反的,在被捕获的引用可能会变为`nil`时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为`nil`。这使我们可以在闭包体内检查它们是否存在。 >注意: -如果捕获的引用绝对不会置为`nil`,应该用无主引用,而不是弱引用。 +如果被捕获的引用绝对不会变为`nil`,应该用无主引用,而不是弱引用。 前面的`HTMLElement`例子中,无主引用是正确的解决循环强引用的方法。这样编写`HTMLElement`类来避免循环强引用: @@ -511,7 +516,7 @@ class HTMLElement { let name: String let text: String? - lazy var asHTML: () -> String = { + lazy var asHTML: Void -> String = { [unowned self] in if let text = self.text { return "<\(self.name)>\(text)\(self.name)>" @@ -526,19 +531,19 @@ class HTMLElement { } deinit { - println("\(name) is being deinitialized") + print("\(name) is being deinitialized") } } ``` -上面的`HTMLElement`实现和之前的实现一致,只是在`asHTML`闭包中多了一个捕获列表。这里,捕获列表是`[unowned self]`,表示“用无主引用而不是强引用来捕获`self`”。 +上面的`HTMLElement`实现和之前的实现一致,除了在`asHTML`闭包中多了一个捕获列表。这里,捕获列表是`[unowned self]`,表示“用无主引用而不是强引用来捕获`self`”。 和之前一样,我们可以创建并打印`HTMLElement`实例: ```swift var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") -println(paragraph!.asHTML()) +print(paragraph!.asHTML()) // prints "hello, world
" ``` diff --git a/source/chapter2/19_Nested_Types.md b/source/chapter2/19_Nested_Types.md index bd03302e..46c4a6bc 100755 --- a/source/chapter2/19_Nested_Types.md +++ b/source/chapter2/19_Nested_Types.md @@ -76,7 +76,7 @@ struct BlackjackCard { ```swift let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades) -println("theAceOfSpades: \(theAceOfSpades.description)") +print("theAceOfSpades: \(theAceOfSpades.description)") // 打印出 "theAceOfSpades: suit is ♠, value is 1 or 11" ``` diff --git a/source/chapter2/20_Type_Casting.md b/source/chapter2/20_Type_Casting.md index cea8fe3d..83929634 100644 --- a/source/chapter2/20_Type_Casting.md +++ b/source/chapter2/20_Type_Casting.md @@ -1,5 +1,5 @@ > 翻译:[xiehurricane](https://github.com/xiehurricane) -> 校对:[happyming](https://github.com/happyming) +> 校对:[happyming](https://github.com/happyming) [yangsiy](https://github.com/yangsiy) # 类型转换(Type Casting) ----------------- @@ -14,16 +14,16 @@ _类型转换_可以判断实例的类型,也可以将实例看做是其父类或者子类的实例。 -类型转换在 Swift 中使用`is` 和 `as`操作符实现。这两个操作符提供了一种简单达意的方式去检查值的类型或者转换它的类型。 +类型转换在 Swift 中使用 `is` 和 `as` 操作符实现。这两个操作符提供了一种简单达意的方式去检查值的类型或者转换它的类型。 -你也可以用来检查一个类是否实现了某个协议,就像在 [Checking for Protocol Conformance](Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_363)部分讲述的一样。 +你也可以用它来检查一个类是否实现了某个协议,就像在 [Checking for Protocol Conformance](Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_363)部分讲述的一样。 ## 定义一个类层次作为例子 -你可以将它用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。这下面的三个代码段定义了一个类层次和一个包含了几个这些类实例的数组,作为类型转换的例子。 +你可以将类型转换用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。下面的三个代码段定义了一个类层次和一个包含了几个这些类实例的数组,作为类型转换的例子。 -第一个代码片段定义了一个新的基础类`MediaItem`。这个类为任何出现在数字媒体库的媒体项提供基础功能。特别的,它声明了一个 `String` 类型的 `name` 属性,和一个`init name`初始化器。(它假定所有的媒体项都有个名称。) +第一个代码片段定义了一个新的基础类 `MediaItem`。这个类为任何出现在数字媒体库的媒体项提供基础功能。特别的,它声明了一个 `String` 类型的 `name` 属性,和一个 `init name` 初始化器。(假定所有的媒体项都有个名称。) ```swift class MediaItem { @@ -34,7 +34,7 @@ class MediaItem { } ``` -下一个代码段定义了 `MediaItem` 的两个子类。第一个子类`Movie`,在父类(或者说基类)的基础上增加了一个 `director`(导演) 属性,和相应的初始化器。第二个类在父类的基础上增加了一个 `artist`(艺术家) 属性,和相应的初始化器: +下一个代码段定义了 `MediaItem` 的两个子类。第一个子类 `Movie` 封装了与电影相关的额外信息,在父类(或者说基类)的基础上增加了一个 `director`(导演)属性,和相应的初始化器。第二个子类 `Song`,在父类的基础上增加了一个 `artist`(艺术家)属性,和相应的初始化器: ```swift class Movie: MediaItem { @@ -54,7 +54,7 @@ class Song: MediaItem { } ``` -最后一个代码段创建了一个数组常量 `library`,包含两个`Movie`实例和三个`Song`实例。`library`的类型是在它被初始化时根据它数组中所包含的内容推断来的。Swift 的类型检测器能够演绎出`Movie` 和 `Song` 有共同的父类 `MediaItem` ,所以它推断出 `[MediaItem]` 类作为 `library` 的类型。 +最后一个代码段创建了一个数组常量 `library`,包含两个 `Movie` 实例和三个 `Song` 实例。`library` 的类型是在它被初始化时根据它数组中所包含的内容推断来的。Swift的类型检测器能够推理出 `Movie` 和 `Song` 有共同的父类 `MediaItem`,所以它推断出 `[MediaItem]` 类作为 `library` 的类型。 ```swift let library = [ @@ -67,14 +67,14 @@ let library = [ // the type of "library" is inferred to be [MediaItem] ``` -在幕后`library` 里存储的媒体项依然是 `Movie` 和 `Song` 类型的,但是,若你迭代它,取出的实例会是 `MediaItem` 类型的,而不是 `Movie` 和 `Song` 类型的。为了让它们作为它们本来的类型工作,你需要检查它们的类型或者向下转换它们的类型到其它类型,就像下面描述的一样。 +在幕后 `library` 里存储的媒体项依然是 `Movie` 和 `Song` 类型的。但是,若你迭代它,依次取出的实例会是 `MediaItem` 类型的,而不是 `Movie` 和 `Song` 类型。为了让它们作为原本的类型工作,你需要检查它们的类型或者向下转换它们到其它类型,就像下面描述的一样。 ## 检查类型(Checking Type) -用类型检查操作符(`is`)来检查一个实例是否属于特定子类型。若实例属于那个子类型,类型检查操作符返回 `true` ,否则返回 `false` 。 +用类型检查操作符(`is`)来检查一个实例是否属于特定子类型。若实例属于那个子类型,类型检查操作符返回 `true`,否则返回 `false`。 -下面的例子定义了两个变量,`movieCount` 和 `songCount`,用来计算数组`library` 中 `Movie` 和 `Song` 类型的实例数量。 +下面的例子定义了两个变量,`movieCount` 和 `songCount`,用来计算数组 `library` 中 `Movie` 和 `Song` 类型的实例数量。 ```swift var movieCount = 0 @@ -88,38 +88,38 @@ for item in library { } } -println("Media library contains \(movieCount) movies and \(songCount) songs") +print("Media library contains \(movieCount) movies and \(songCount) songs") // prints "Media library contains 2 movies and 3 songs" ``` -示例迭代了数组 `library` 中的所有项。每一次, `for`-`in` 循环设置 +示例迭代了数组 `library` 中的所有项。每一次,`for`-`in` 循环设置 `item` 为数组中的下一个 `MediaItem`。 -若当前 `MediaItem` 是一个 `Movie` 类型的实例, `item is Movie` 返回 +若当前 `MediaItem` 是一个 `Movie` 类型的实例,`item is Movie` 返回 `true`,相反返回 `false`。同样的,`item is -Song`检查item是否为`Song`类型的实例。在循环结束后,`movieCount` 和 `songCount`的值就是被找到属于各自的类型的实例数量。 +Song` 检查item是否为 `Song` 类型的实例。在循环结束后,`movieCount` 和 `songCount` 的值就是被找到属于各自的类型的实例数量。 ## 向下转型(Downcasting) -某类型的一个常量或变量可能在幕后实际上属于一个子类。你可以相信,上面就是这种情况。你可以尝试向下转到它的子类型,用类型转换操作符(`as`) +某类型的一个常量或变量可能在幕后实际上属于一个子类。当确定是这种情况时,你可以尝试向下转到它的子类型,用类型转换操作符(`as?` 或 `as!`) -因为向下转型可能会失败,类型转型操作符带有两种不同形式。可选形式( optional form) `as?` 返回一个你试图下转成的类型的可选值(optional value)。强制形式 `as` 把试图向下转型和强制解包(force-unwraps)结果作为一个混合动作。 +因为向下转型可能会失败,类型转型操作符带有两种不同形式。条件形式(conditional form) `as?` 返回一个你试图向下转成的类型的可选值(optional value)。强制形式 `as!` 把试图向下转型和强制解包(force-unwraps)结果作为一个混合动作。 -当你不确定向下转型可以成功时,用类型转换的可选形式(`as?`)。可选形式的类型转换总是返回一个可选值(optional value),并且若下转是不可能的,可选值将是 `nil` 。这使你能够检查向下转型是否成功。 +当你不确定向下转型可以成功时,用类型转换的条件形式(`as?`)。条件形式的类型转换总是返回一个可选值(optional value),并且若下转是不可能的,可选值将是 `nil`。这使你能够检查向下转型是否成功。 -只有你可以确定向下转型一定会成功时,才使用强制形式。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。 +只有你可以确定向下转型一定会成功时,才使用强制形式(`as!`)。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。 -下面的例子,迭代了`library`里的每一个 `MediaItem` ,并打印出适当的描述。要这样做,`item`需要真正作为`Movie` 或 `Song`的类型来使用。不仅仅是作为 `MediaItem`。为了能够使用`Movie` 或 `Song`的 `director` 或 `artist`属性,这是必要的。 +下面的例子,迭代了 `library` 里的每一个 `MediaItem`,并打印出适当的描述。要这样做,`item` 需要真正作为 `Movie` 或 `Song` 的类型来使用,不仅仅是作为 `MediaItem`。为了能够在描述中使用 `Movie` 或 `Song` 的 `director` 或 `artist` 属性,这是必要的。 -在这个示例中,数组中的每一个`item`可能是 `Movie` 或 `Song`。 事前你不知道每个`item`的真实类型,所以这里使用可选形式的类型转换 (`as?`)去检查循环里的每次下转。 +在这个示例中,数组中的每一个 `item` 可能是 `Movie` 或 `Song`。事前你不知道每个 `item` 的真实类型,所以这里使用条件形式的类型转换(`as?`)去检查循环里的每次下转。 ```swift for item in library { if let movie = item as? Movie { - println("Movie: '\(movie.name)', dir. \(movie.director)") + print("Movie: '\(movie.name)', dir. \(movie.director)") } else if let song = item as? Song { - println("Song: '\(song.name)', by \(song.artist)") + print("Song: '\(song.name)', by \(song.artist)") } } @@ -131,18 +131,18 @@ for item in library { ``` 示例首先试图将 `item` 下转为 `Movie`。因为 `item` 是一个 `MediaItem` -类型的实例,它可能是一个`Movie`;同样,它可能是一个 `Song`,或者仅仅是基类 -`MediaItem`。因为不确定,`as?`形式在试图下转时将返还一个可选值。 `item as Movie` 的返回值是`Movie?`类型或 “optional `Movie`”。 +类型的实例,它可能是一个 `Movie`;同样,它也可能是一个 `Song`,或者仅仅是基类 +`MediaItem`。因为不确定,`as?`形式在试图下转时将返回一个可选值。`item as? Movie` 的返回值是 `Movie?` 或 “可选 `Movie`”类型。 当向下转型为 `Movie` 应用在两个 `Song` -实例时将会失败。为了处理这种情况,上面的例子使用了可选绑定(optional binding)来检查可选 `Movie`真的包含一个值(这个是为了判断下转是否成功。)可选绑定是这样写的“`if let movie = item as? Movie`”,可以这样解读: +实例时将会失败。为了处理这种情况,上面的例子使用了可选绑定(optional binding)来检查可选 `Movie` 真的包含一个值(这个是为了判断下转是否成功。)可选绑定是这样写的“`if let movie = item as? Movie`”,可以这样解读: -“尝试将 `item` 转为 `Movie`类型。若成功,设置一个新的临时常量 `movie` 来存储返回的可选`Movie`” +“尝试将 `item` 转为 `Movie` 类型。若成功,设置一个新的临时常量 `movie` 来存储返回的可选 `Movie`” -若向下转型成功,然后`movie`的属性将用于打印一个`Movie`实例的描述,包括它的导演的名字`director`。当`Song`被找到时,一个相近的原理被用来检测 `Song` 实例和打印它的描述。 +若向下转型成功,然后 `movie` 的属性将用于打印一个 `Movie` 实例的描述,包括它的导演的名字 `director` 。相近的原理被用来检测 `Song` 实例,当 `Song` 被找到时则打印它的描述(包含 `artist` 的名字)。 -> 注意: -转换没有真的改变实例或它的值。潜在的根本的实例保持不变;只是简单地把它作为它被转换成的类来使用。 +> 注意: +> 转换没有真的改变实例或它的值。潜在的根本的实例保持不变;只是简单地把它作为它被转换成的类来使用。 ## `Any`和`AnyObject`的类型转换 @@ -152,12 +152,12 @@ Swift为不确定类型提供了两种特殊类型别名: * `AnyObject`可以代表任何class类型的实例。 * `Any`可以表示任何类型,包括方法类型(function types)。 -> 注意: -只有当你明确的需要它的行为和功能时才使用`Any`和`AnyObject`。在你的代码里使用你期望的明确的类型总是更好的。 +> 注意: +> 只有当你明确的需要它的行为和功能时才使用`Any`和`AnyObject`。在你的代码里使用你期望的明确的类型总是更好的。 ### `AnyObject`类型 -当需要在工作中使用 Cocoa APIs,它一般接收一个`[AnyObject]`类型的数组,或者说“一个任何对象类型的数组”。这是因为 Objective-C 没有明确的类型化数组。但是,你常常可以确定包含在仅从你知道的 API 信息提供的这样一个数组中的对象的类型。 +当在工作中使用 Cocoa APIs,我们一般会接收一个`[AnyObject]`类型的数组,或者说“一个任何对象类型的数组”。这是因为 Objective-C 没有明确的类型化数组。但是,你常常可以从 API 提供的信息中清晰地确定数组中对象的类型。 在这些情况下,你可以使用强制形式的类型转换(`as`)来下转在数组中的每一项到比 `AnyObject` 更明确的类型,不需要可选解析(optional unwrapping)。 @@ -171,23 +171,23 @@ let someObjects: [AnyObject] = [ ] ``` -因为知道这个数组只包含 `Movie` 实例,你可以直接用(`as`)下转并解包到不可选的`Movie`类型(ps:其实就是我们常用的正常类型,这里是为了和可选类型相对比)。 +因为知道这个数组只包含 `Movie` 实例,你可以直接用(`as!`)下转并解包到不可选的`Movie`类型: ```swift for object in someObjects { - let movie = object as Movie - println("Movie: '\(movie.name)', dir. \(movie.director)") + let movie = object as! Movie + print("Movie: '\(movie.name)', dir. \(movie.director)") } // Movie: '2001: A Space Odyssey', dir. Stanley Kubrick // Movie: 'Moon', dir. Duncan Jones // Movie: 'Alien', dir. Ridley Scott ``` -为了变为一个更短的形式,下转`someObjects`数组为`[Movie]`类型来代替下转每一项方式。 +为了变为一个更短的形式,下转`someObjects`数组为`[Movie]`类型来代替下转数组中每一项的方式。 ```swift for movie in someObjects as! [Movie] { - println("Movie: '\(movie.name)', dir. \(movie.director)") + print("Movie: '\(movie.name)', dir. \(movie.director)") } // Movie: '2001: A Space Odyssey', dir. Stanley Kubrick // Movie: 'Moon', dir. Duncan Jones @@ -196,7 +196,7 @@ for movie in someObjects as! [Movie] { ### `Any`类型 -这里有个示例,使用 `Any` 类型来和混合的不同类型一起工作,包括非`class`类型。它创建了一个可以存储`Any`类型的数组 `things`。 +这里有个示例,使用 `Any` 类型来和混合的不同类型一起工作,包括方法类型和非 `class` 类型。它创建了一个可以存储`Any`类型的数组 `things`。 ```swift var things = [Any]() @@ -211,33 +211,33 @@ things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman")) things.append({ (name: String) -> String in "Hello, \(name)" }) ``` -`things` 数组包含两个 `Int` 值,2个 `Double` 值,1个 `String` 值,一个元组 `(Double, Double)` ,Ivan Reitman 导演的电影“Ghostbusters”。 +`things` 数组包含两个 `Int` 值,2个 `Double` 值,1个 `String` 值,一个元组 `(Double, Double)` ,电影“Ghostbusters”,和一个获取 `String` 值并返回另一个 `String` 值的闭包表达式。 -你可以在 `switch` `cases`里用`is` 和 `as` 操作符来发觉只知道是 `Any` 或 `AnyObject`的常量或变量的类型。 下面的示例迭代 `things`数组中的每一项的并用`switch`语句查找每一项的类型。这几种`switch`语句的情形绑定它们匹配的值到一个规定类型的常量,让它们可以打印它们的值: +你可以在 `switch` 表达式的cases中使用 `is` 和 `as` 操作符来发觉只知道是 `Any` 或 `AnyObject` 的常量或变量的类型。下面的示例迭代 `things` 数组中的每一项的并用`switch`语句查找每一项的类型。这几种 `switch` 语句的情形绑定它们匹配的值到一个规定类型的常量,让它们的值可以被打印: ```swift for thing in things { switch thing { case 0 as Int: - println("zero as an Int") + print("zero as an Int") case 0 as Double: - println("zero as a Double") + print("zero as a Double") case let someInt as Int: - println("an integer value of \(someInt)") + print("an integer value of \(someInt)") case let someDouble as Double where someDouble > 0: - println("a positive double value of \(someDouble)") + print("a positive double value of \(someDouble)") case is Double: - println("some other double value that I don't want to print") + print("some other double value that I don't want to print") case let someString as String: - println("a string value of \"\(someString)\"") + print("a string value of \"\(someString)\"") case let (x, y) as (Double, Double): - println("an (x, y) point at \(x), \(y)") + print("an (x, y) point at \(x), \(y)") case let movie as Movie: - println("a movie called '\(movie.name)', dir. \(movie.director)") + print("a movie called '\(movie.name)', dir. \(movie.director)") case let stringConverter as String -> String: - println(stringConverter("Michael")) + print(stringConverter("Michael")) default: - println("something else") + print("something else") } } @@ -252,5 +252,5 @@ for thing in things { ``` -> 注意: -在一个switch语句的case中使用强制形式的类型转换操作符(as, 而不是 as?)来检查和转换到一个明确的类型。在 switch case 语句的内容中这种检查总是安全的。 +> 注意: +> 在一个switch语句的case中使用强制形式的类型转换操作符(as, 而不是 as?)来检查和转换到一个明确的类型。在 `switch` case 语句的内容中这种检查总是安全的。 diff --git a/source/chapter2/23_Generics.md b/source/chapter2/23_Generics.md index c114a436..2fa90bc5 100644 --- a/source/chapter2/23_Generics.md +++ b/source/chapter2/23_Generics.md @@ -1,5 +1,5 @@ -> 翻译:[takalard](https://github.com/takalard) +> 翻译:[takalard](https://github.com/takalard) [SergioChan](https://github.com/SergioChan) > 校对:[lifedim](https://github.com/lifedim) # 泛型 @@ -13,6 +13,7 @@ - [类型参数](#type_parameters) - [命名类型参数](#naming_type_parameters) - [泛型类型](#generic_types) +- [扩展一个泛型类型](#extending_a_generic_type) - [类型约束](#type_constraints) - [关联类型](#associated_types) - [`Where`语句](#where_clauses) @@ -27,7 +28,7 @@ 这里是一个标准的,非泛型函数`swapTwoInts`,用来交换两个Int值: ```swift -func swapTwoInts(inout a: Int, inout b: Int) { +func swapTwoInts(inout a: Int, inout _ b: Int) { let temporaryA = a a = b b = temporaryA @@ -36,34 +37,34 @@ func swapTwoInts(inout a: Int, inout b: Int) { 这个函数使用写入读出(in-out)参数来交换`a`和`b`的值,请参考[写入读出参数](../chapter2/06_Functions.html)。 -`swapTwoInts`函数可以交换`b`的原始值到`a`,也可以交换a的原始值到`b`,你可以调用这个函数交换两个`Int`变量值: +`swapTwoInts(_:_:)`函数可以交换`b`的原始值到`a`,也可以交换a的原始值到`b`,你可以调用这个函数交换两个`Int`变量值: ```swift var someInt = 3 var anotherInt = 107 swapTwoInts(&someInt, &anotherInt) -println("someInt is now \(someInt), and anotherInt is now \(anotherInt)") +print("someInt is now \(someInt), and anotherInt is now \(anotherInt)") // 输出 "someInt is now 107, and anotherInt is now 3" ``` -`swapTwoInts`函数是非常有用的,但是它只能交换`Int`值,如果你想要交换两个`String`或者`Double`,就不得不写更多的函数,如 `swapTwoStrings`和`swapTwoDoublesfunctions `,如同如下所示: +`swapTwoInts(_:_:)`函数是非常有用的,但是它只能交换`Int`值,如果你想要交换两个`String`或者`Double`,就不得不写更多的函数,如 `swapTwoStrings`和`swapTwoDoubles(_:_:)`,如同如下所示: ```swift -func swapTwoStrings(inout a: String, inout b: String) { +func swapTwoStrings(inout a: String, inout _ b: String) { let temporaryA = a a = b b = temporaryA } -func swapTwoDoubles(inout a: Double, inout b: Double) { +func swapTwoDoubles(inout a: Double, inout _ b: Double) { let temporaryA = a a = b b = temporaryA } ``` -你可能注意到 `swapTwoInts`、 `swapTwoStrings`和`swapTwoDoubles`函数功能都是相同的,唯一不同之处就在于传入的变量类型不同,分别是`Int`、`String`和`Double`。 +你可能注意到 `swapTwoInts`、 `swapTwoStrings`和`swapTwoDoubles(_:_:)`函数功能都是相同的,唯一不同之处就在于传入的变量类型不同,分别是`Int`、`String`和`Double`。 但实际应用中通常需要一个用处更强大并且尽可能的考虑到更多的灵活性单个函数,可以用来交换两个任何类型值,很幸运的是,泛型代码帮你解决了这种问题。(一个这种泛型函数后面已经定义好了。) @@ -73,29 +74,29 @@ func swapTwoDoubles(inout a: Double, inout b: Double) { ## 泛型函数 -`泛型函数`可以工作于任何类型,这里是一个上面`swapTwoInts`函数的泛型版本,用于交换两个值: +`泛型函数`可以工作于任何类型,这里是一个上面`swapTwoInts(_:_:)`函数的泛型版本,用于交换两个值: ```swift -func swapTwoValues\`。例如,class 不是合法的标识符,但可以使用 \`class\`。反引号不属于标识符的一部分,\`x\` 和 `x` 表示同一标识符。
-
-闭包(*closure*)中如果没有明确指定参数名称,参数将被隐式命名为 $0、$1、$2... 这些命名在闭包作用域内是合法的标识符。
-
-> 标识符语法
-> *标识符* → [*标识符头(Head)*](LexicalStructure.html#identifier_head) [*标识符字符列表*](LexicalStructure.html#identifier_characters) _可选_
-> *标识符* → **`** [*标识符头(Head)*](LexicalStructure.html#identifier_head) [*标识符字符列表*](LexicalStructure.html#identifier_characters) _可选_ **`**
-> *标识符* → [*隐式参数名*](LexicalStructure.html#implicit_parameter_name)
-> *标识符列表* → [*标识符*](LexicalStructure.html#identifier) | [*标识符*](LexicalStructure.html#identifier) **,** [*标识符列表*](LexicalStructure.html#identifier_list)
-> *标识符头(Head)* → Upper- or lowercase letter A through Z
-> *标识符头(Head)* → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA
-> *标识符头(Head)* → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF
-> *标识符头(Head)* → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF
-> *标识符头(Head)* → U+1E00–U+1FFF
-> *标识符头(Head)* → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F
-> *标识符头(Head)* → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793
-> *标识符头(Head)* → U+2C00–U+2DFF or U+2E80–U+2FFF
-> *标识符头(Head)* → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF
-> *标识符头(Head)* → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44
-> *标识符头(Head)* → U+FE47–U+FFFD
-> *标识符头(Head)* → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD
-> *标识符头(Head)* → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD
-> *标识符头(Head)* → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD
-> *标识符头(Head)* → U+D0000–U+DFFFD or U+E0000–U+EFFFD
-> *标识符字符* → 数值 0 到 9
-> *标识符字符* → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F
-> *标识符字符* → [*标识符头(Head)*](LexicalStructure.html#identifier_head)
-> *标识符字符列表* → [*标识符字符*](LexicalStructure.html#identifier_character) [*标识符字符列表*](LexicalStructure.html#identifier_characters) _可选_
-> *隐式参数名* → **$** [*十进制数字列表*](LexicalStructure.html#decimal_digits)
-
-
-## 关键字
-
-被保留的关键字(*keywords*)不允许用作标识符,除非被反引号转义,参见 [标识符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_796)。
-
-* **用作声明的关键字:** *class*、*deinit*、*enum*、*extension*、*func*、*import*、*init*、*let*、*protocol*、*static*、*struct*、*subscript*、*typealias*、*var*
-* **用作语句的关键字:** *break*、*case*、*continue*、*default*、*do*、*else*、*fallthrough*、*if*、*in*、*for*、*return*、*switch*、*where*、*while*
-* **用作表达和类型的关键字:** *as*、*dynamicType*、*is*、*new*、*super*、*self*、*Self*、*Type*、*\_\_COLUMN\_\_*、*\_\_FILE\_\_*、*\_\_FUNCTION\_\_*、*\_\_LINE\_\_*
-* **特定上下文中被保留的关键字:** *associativity*、*didSet*、*get*、*infix*、*inout*、*left*、*mutating*、*none*、*nonmutating*、*operator*、*override*、*postfix*、
- *precedence*、*prefix*、*right*、*set*、*unowned*、*unowned(safe)*、*unowned(unsafe)*、*weak*、*willSet*,这些关键字在特定上下文之外可以被用于标识符。
-
-
-## 字面量
-
-字面值表示整型、浮点型数字或文本类型的值,举例如下:
-
-```swift
-42 // 整型字面量
-3.14159 // 浮点型字面量
-"Hello, world!" // 文本型字面量
-```
-
-> 字面量语法
-> *字面量* → [*整型字面量*](LexicalStructure.html#integer_literal) | [*浮点数字面量*](LexicalStructure.html#floating_point_literal) | [*字符串字面量*](LexicalStructure.html#string_literal)
-
-### 整型字面量
-
-整型字面量(*integer literals*)表示未指定精度整型数的值。整型字面量默认用十进制表示,可以加前缀来指定其他的进制,二进制字面量加 `0b`,八进制字面量加 `0o`,十六进制字面量加 `0x`。
-
-十进制字面量包含数字 `0` 至 `9`。二进制字面量只包含 `0` 或 `1`,八进制字面量包含数字 `0` 至 `7`,十六进制字面量包含数字 `0` 至 `9` 以及字母 `A` 至 `F` (大小写均可)。
-
-负整数的字面量在数字前加减号 `-`,比如 `-42`。
-
-允许使用下划线 `_` 来增加数字的可读性,下划线不会影响字面量的值。整型字面量也可以在数字前加 `0`,同样不会影响字面量的值。
-
-```swift
-1000_000 // 等于 1000000
-005 // 等于 5
-```
-
-除非特殊指定,整型字面量的默认类型为 Swift 标准库类型中的 `Int`。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 [整数类型](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_411)。
-
-> 整型字面量语法
-> *整型字面量* → [*二进制字面量*](LexicalStructure.html#binary_literal)
-> *整型字面量* → [*八进制字面量*](LexicalStructure.html#octal_literal)
-> *整型字面量* → [*十进制字面量*](LexicalStructure.html#decimal_literal)
-> *整型字面量* → [*十六进制字面量*](LexicalStructure.html#hexadecimal_literal)
-> *二进制字面量* → **0b** [*二进制数字*](LexicalStructure.html#binary_digit) [*二进制字面量字符列表*](LexicalStructure.html#binary_literal_characters) _可选_
-> *二进制数字* → 数值 0 到 1
-> *二进制字面量字符* → [*二进制数字*](LexicalStructure.html#binary_digit) | **_**
-> *二进制字面量字符列表* → [*二进制字面量字符*](LexicalStructure.html#binary_literal_character) [*二进制字面量字符列表*](LexicalStructure.html#binary_literal_characters) _可选_
-> *八进制字面量* → **0o** [*八进字数字*](LexicalStructure.html#octal_digit) [*八进制字符列表*](LexicalStructure.html#octal_literal_characters) _可选_
-> *八进字数字* → 数值 0 到 7
-> *八进制字符* → [*八进字数字*](LexicalStructure.html#octal_digit) | **_**
-> *八进制字符列表* → [*八进制字符*](LexicalStructure.html#octal_literal_character) [*八进制字符列表*](LexicalStructure.html#octal_literal_characters) _可选_
-> *十进制字面量* → [*十进制数字*](LexicalStructure.html#decimal_digit) [*十进制字符列表*](LexicalStructure.html#decimal_literal_characters) _可选_
-> *十进制数字* → 数值 0 到 9
-> *十进制数字列表* → [*十进制数字*](LexicalStructure.html#decimal_digit) [*十进制数字列表*](LexicalStructure.html#decimal_digits) _可选_
-> *十进制字符* → [*十进制数字*](LexicalStructure.html#decimal_digit) | **_**
-> *十进制字符列表* → [*十进制字符*](LexicalStructure.html#decimal_literal_character) [*十进制字符列表*](LexicalStructure.html#decimal_literal_characters) _可选_
-> *十六进制字面量* → **0x** [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制字面量字符列表*](LexicalStructure.html#hexadecimal_literal_characters) _可选_
-> *十六进制数字* → 数值 0 到 9, a through f, or A through F
-> *十六进制字符* → [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) | **_**
-> *十六进制字面量字符列表* → [*十六进制字符*](LexicalStructure.html#hexadecimal_literal_character) [*十六进制字面量字符列表*](LexicalStructure.html#hexadecimal_literal_characters) _可选_
-
-### 浮点型字面量
-
-浮点型字面量(*floating-point literals*)表示未指定精度浮点数的值。
-
-浮点型字面量默认用十进制表示(无前缀),也可以用十六进制表示(加前缀 `0x`)。
-
-十进制浮点型字面量(*decimal floating-point literals*)由十进制数字串后跟小数部分或指数部分(或两者皆有)组成。十进制小数部分由小数点 `.` 后跟十进制数字串组成。指数部分由大写或小写字母 `e` 后跟十进制数字串组成,这串数字表示 `e` 之前的数量乘以 10 的几次方。例如:`1.25e2` 表示 `1.25 ⨉ 10^2`,也就是 `125.0`;同样,`1.25e-2` 表示 `1.25 ⨉ 10^-2`,也就是 `0.0125`。
-
-十六进制浮点型字面量(*hexadecimal floating-point literals*)由前缀 `0x` 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字串组成。指数部分由大写或小写字母 `p` 后跟十进制数字串组成,这串数字表示 `p` 之前的数量乘以 2 的几次方。例如:`0xFp2` 表示 `15 ⨉ 2^2`,也就是 `60`;同样,`0xFp-2` 表示 `15 ⨉ 2^-2`,也就是 `3.75`。
-
-与整型字面量不同,负的浮点型字面量由一元运算符减号 `-` 和浮点型字面量组成,例如 `-42.0`。这代表一个表达式,而不是一个浮点整型字面量。
-
-允许使用下划线 `_` 来增强可读性,下划线不会影响字面量的值。浮点型字面量也可以在数字前加 `0`,同样不会影响字面量的值。
-
-```swift
-10_000.56 // 等于 10000.56
-005000.76 // 等于 5000.76
-```
-
-除非特殊指定,浮点型字面量的默认类型为 Swift 标准库类型中的 `Double`,表示64位浮点数。Swift 标准库也定义 `Float` 类型,表示32位浮点数。
-
-> 浮点型字面量语法
-> *浮点数字面量* → [*十进制字面量*](LexicalStructure.html#decimal_literal) [*十进制分数*](LexicalStructure.html#decimal_fraction) _可选_ [*十进制指数*](LexicalStructure.html#decimal_exponent) _可选_
-> *浮点数字面量* → [*十六进制字面量*](LexicalStructure.html#hexadecimal_literal) [*十六进制分数*](LexicalStructure.html#hexadecimal_fraction) _可选_ [*十六进制指数*](LexicalStructure.html#hexadecimal_exponent)
-> *十进制分数* → **.** [*十进制字面量*](LexicalStructure.html#decimal_literal)
-> *十进制指数* → [*浮点数e*](LexicalStructure.html#floating_point_e) [*正负号*](LexicalStructure.html#sign) _可选_ [*十进制字面量*](LexicalStructure.html#decimal_literal)
-> *十六进制分数* → **.** [*十六进制字面量*](LexicalStructure.html#hexadecimal_literal) _可选_
-> *十六进制指数* → [*浮点数p*](LexicalStructure.html#floating_point_p) [*正负号*](LexicalStructure.html#sign) _可选_ [*十六进制字面量*](LexicalStructure.html#hexadecimal_literal)
-> *浮点数e* → **e** | **E**
-> *浮点数p* → **p** | **P**
-> *正负号* → **+** | **-**
-
-### 文本型字面量
-
-文本型字面量(*string literal*)由双引号中的字符串组成,形式如下:
-
-```swift
-"characters"
-```
-
-文本型字面量中不能包含未转义的双引号 `"`、未转义的反斜线`\`、回车符(*carriage return*)或换行符(*line feed*)。
-
-可以在文本型字面量中使用的转义特殊符号如下:
-
-* 空字符(Null Character)`\0`
-* 反斜线(Backslash)`\\`
-* 水平 Tab (Horizontal Tab)`\t`
-* 换行符(Line Feed)`\n`
-* 回车符(Carriage Return)`\r`
-* 双引号(Double Quote)`\"`
-* 单引号(Single Quote)`\'`
-
-字符也可以用以下方式表示:
-
-* `\x` 后跟两位十六进制数字
-* `\u` 后跟四位十六进制数字
-* `\U` 后跟八位十六进制数字
-
-后跟的数字表示一个 Unicode 码点。
-
-文本型字面量允许在反斜线小括号 `\()` 中插入表达式的值。插入表达式(*interpolated expression*)不能包含未转义的双引号 `"`、反斜线 `\`、回车符或者换行符。表达式值的类型必须在 *String* 类中有对应的初始化方法。
-
-例如,以下所有文本型字面量的值相同:
-
-```swift
-"1 2 3"
-"1 2 \(3)"
-"1 2 \(1 + 2)"
-var x = 3; "1 2 \(x)"
-```
-
-文本型字面量的默认类型为 `String`。组成字符串的字符类型为 `Character`。更多有关 `String` 和 `Character` 的信息请参照 [字符串和字符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_368)。
-
-> 字符型字面量语法
-> *字符串字面量* → **"** [*引用文本*](LexicalStructure.html#quoted_text) **"**
-> *引用文本* → [*引用文本条目*](LexicalStructure.html#quoted_text_item) [*引用文本*](LexicalStructure.html#quoted_text) _可选_
-> *引用文本条目* → [*转义字符*](LexicalStructure.html#escaped_character)
-> *引用文本条目* → **\(** [*表达式*](..\chapter3\04_Expressions.html#expression) **)**
-> *引用文本条目* → 除了", \, U+000A, or U+000D的所有Unicode的字符
-> *转义字符* → **\0** | **\\** | **\t** | **\n** | **\r** | **\"** | **\'**
-> *转义字符* → **\x** [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit)
-> *转义字符* → **\u** [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit)
-> *转义字符* → **\U** [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit) [*十六进制数字*](LexicalStructure.html#hexadecimal_digit)
-
-
-## 运算符
-
-Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基础运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-XID_70) 和 [高级运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_28) 中进行了阐述。这里将描述哪些字符能用作运算符。
-
-运算符由一个或多个以下字符组成:
-`/`、`=`、`-`、`+`、`!`、`*`、`%`、`<`、`>`、`&`、`|`、`^`、`~`、`.`。也就是说,标记 `=`, `->`、`//`、`/*`、`*/`、`.` 以及一元前缀运算符 `&` 属于保留字,这些标记不能被重写或用于自定义运算符。
-
-运算符两侧的空白被用来区分该运算符是否为前缀运算符(*prefix operator*)、后缀运算符(*postfix operator*)或二元运算符(*binary operator*)。规则总结如下:
-
-* 如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:`a+b` 和 `a + b` 中的运算符 `+` 被看作二元运算符。
-* 如果运算符只有左侧空白,将被看作前缀一元运算符。例如 `a ++b` 中的 `++` 被看作前缀一元运算符。
-* 如果运算符只有右侧空白,将被看作后缀一元运算符。例如 `a++ b` 中的 `++` 被看作后缀一元运算符。
-* 如果运算符左侧没有空白并紧跟 `.`,将被看作后缀一元运算符。例如 `a++.b` 中的 `++` 被看作后缀一元运算符(同理, `a++ . b` 中的 `++` 是后缀一元运算符而 `a ++ .b` 中的 `++` 不是).
-
-鉴于这些规则,运算符前的字符 `(`、`[` 和 `{` ;运算符后的字符 `)`、`]` 和 `}` 以及字符 `,`、`;` 和 `:` 都将用于空白检测。
-
-以上规则需注意一点,如果运算符 `!` 或 `?` 左侧没有空白,则不管右侧是否有空白都将被看作后缀运算符。如果将 `?` 用作可选类型(*optional type*)修饰,左侧必须无空白。如果用于条件运算符 `? :`,必须两侧都有空白。
-
-在特定构成中 ,以 `<` 或 `>` 开头的运算符会被分离成两个或多个标记,剩余部分以同样的方式会被再次分离。因此,在 `Dictionary\`class\`。反引号不属于标识符的一部分,\`x\` 和 `x` 表示同一标识符。
+
+闭包(*closure*)中如果没有明确指定参数名称,参数将被隐式命名为 `$0`、`$1`、`$2`等等。 这些命名在闭包作用域范围内是合法的标识符。
+
+> 标识符语法
+
+> *标识符* → [*头部标识符*](#identifier_head) [*标识符字符组*](#identifier_characters)可选
+> *标识符* → \`[*头部标识符*](#identifier_head) [*标识符字符组*](#identifier_characters)可选\`
+> *标识符* → [*隐式参数名*](#implicit_parameter_name)
+> *标识符列表* → [*标识符*](#identifier) | [*标识符*](#identifier) **,** [*标识符列表*](#identifier_list)
+
+> *头部标识符* → 大写或小写字母 A - Z
+> *头部标识符* → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA
+> *头部标识符* → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF
+> *头部标识符* → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF
+> *头部标识符* → U+1E00–U+1FFF
+> *头部标识符* → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F
+> *头部标识符* → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793
+> *头部标识符* → U+2C00–U+2DFF or U+2E80–U+2FFF
+> *头部标识符* → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF
+> *头部标识符* → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44
+> *头部标识符* → U+FE47–U+FFFD
+> *头部标识符* → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD
+> *头部标识符* → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD
+> *头部标识符* → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD
+> *头部标识符* → U+D0000–U+DFFFD or U+E0000–U+EFFFD
+> *标识符字符* → 数值 0 - 9
+> *标识符字符* → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F
+> *标识符字符* → [*头部标识符*](#identifier_head)
+
+> *标识符字符组* → [*标识符字符*](#identifier_character) [*标识符字符列表*](#identifier_characters)可选
+
+> *隐式参数名* → **$** [*十进制数字列表*](#decimal_digits)
+
+
+## 关键字和符号
+
+下面这些被保留的关键字(*keywords*)不允许用作标识符,除非被反引号转义,具体描述请参考 [标识符](#identifiers)。
+
+* **用在声明中的关键字:** *class*、*deinit*、*enum*、*extension*、*func*、*import*、*init*、*let*、*protocol*、*static*、*struct*、*subscript*、*typealias*、*var*
+* **用在语句中的关键字:** *break*、*case*、*continue*、*default*、*do*、*else*、*fallthrough*、*if*、*in*、*for*、*return*、*switch*、*where*、*while*
+* **用在表达式和类型中的关键字:** *as*、*dynamicType*、*is*、*new*、*super*、*self*、*Self*、*Type*、*\_\_COLUMN\_\_*、*\_\_FILE\_\_*、*\_\_FUNCTION\_\_*、*\_\_LINE\_\_*
+* **用在模式中的关键字:** *\_*
+* **特定上下文中被保留的关键字:** *associativity*、*didSet*、*get*、*infix*、*inout*、*left*、*mutating*、*none*、*nonmutating*、*operator*、*override*、*postfix*、*precedence*、*prefix*、*right*、*set*、*unowned*、*unowned(safe)*、*unowned(unsafe)*、*weak*、*willSet*,这些关键字在特定上下文之外可以被用于标识符。
+
+以下标记被当作保留符号,不能用于自定义操作符:`(`、`)`、`{`、`}`、`[`、`]`、`.`、`,`、`:`、`;`、`=`、`@`、`#`、`&(作为前缀操作符)`、`->`、`` `、`?` 和 `!(作为后缀操作符)`。
+
+
+## 字面量
+
+字面量是用来表示源码中某种特定类型的值,比如一个数字或字符串。
+
+下面是字面量的一些示例:
+
+```swift
+42 // 整型字面量
+3.14159 // 浮点型字面量
+"Hello, world!" // 字符串型字面量
+true // 布尔型字面量
+```
+
+字面量本身并不包含类型信息。事实上,一个字面量会被解析为拥有无限的精度,然后 Swift 的类型推导会尝试去推导出这个字面量的类型。比如,在 `let x: Int8 = 42` 这个声明中,Swift 使用了显式类型标注(`: Int8`)来推导出 `42` 这个整型字面量的类型是 `Int8`。如果没有可用的类型信息, Swift 则会从标准库中定义的字面量类型中推导出一个默认的类型。整型字面量的默认类型是 `Int`,浮点型字面量的默认类型是 `Double`,字符串型字面量的默认类型是 `String`,布尔型字面量的默认类型是 `Bool`。比如,在 `let str = "Hello, world"` 这个声明中,字符串 `"Hello, world"`的默认推导类型就是 `String`。
+
+当为一个字面量值指定了类型标注的时候,这个注解的类型必须能通过这个字面量值实例化后得到。也就是说,这个类型必须遵守这些 Swift 标准库协议中的一个:整型字面量的`IntegerLiteralConvertible`协议、符点型字面量的`FloatingPointLiteralConvertible`协议、字符串字面量的`StringLiteralConvertible`协议以及布尔型字面量的`BooleanLiteralConvertible`协议。比如,`Int8` 遵守了 `IntegerLiteralConvertible`协议,因此它能在 `let x: Int8 = 42` 这个声明中作为整型字面量 `42` 的类型标注。
+
+> 字面量语法
+> *字面量* → [*数字型字面量*](#numeric_literal) | [*字符串型字面量*](#string_literal) | [*布尔型字面量*](#boolean_literal) | [*nil型字面量*](#nil_literal)
+
+> *数字型字面量* → -可选[*整型字面量*](#integer_literal) | -可选[*符点型字面量*](#floating_point_literal)
+> *布尔型字面量* → **true** | **false**
+> *nil型字面量* → **nil**
+
+### 整型字面量
+
+整型字面量(*integer literals*)表示未指定精度整型数的值。整型字面量默认用十进制表示,可以加前缀来指定其他的进制,二进制字面量加 `0b`,八进制字面量加 `0o`,十六进制字面量加 `0x`。
+
+十进制字面量包含数字 `0` 至 `9`。二进制字面量只包含 `0` 或 `1`,八进制字面量包含数字 `0` 至 `7`,十六进制字面量包含数字 `0` 至 `9` 以及字母 `A` 至 `F` (大小写均可)。
+
+负整数的字面量在整型字面量前加减号 `-`,比如 `-42`。
+
+整型字面面可以使用下划线 `_` 来增加数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,并不会影响字面量的值。
+
+除非特别指定,整型字面量的默认推导类型为 Swift 标准库类型中的 `Int`。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 [整数类型](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID323)。
+
+> 整型字面量语法
+> *整型字面量* → [*二进制字面量*](#binary_literal)
+> *整型字面量* → [*八进制字面量*](#octal_literal)
+> *整型字面量* → [*十进制字面量*](#decimal_literal)
+> *整型字面量* → [*十六进制字面量*](#hexadecimal_literal)
+
+> *二进制字面量* → **0b** [*二进制数字*](#binary_digit) [*二进制字面量字符组*](#binary_literal_characters)可选
+> *二进制数字* → 数值 0 到 1
+> *二进制字面量字符* → [*二进制数字*](#binary_digit) | _
+> *二进制字面量字符组* → [*二进制字面量字符*](#binary_literal_character) [*二进制字面量字符组*](#binary_literal_characters)可选
+
+> *八进制字面量* → **0o** [*八进字数字*](#octal_digit) [*八进制字符列表*](#octal_literal_characters)可选
+> *八进字数字* → 数值 0 到 7
+> *八进制字符* → [*八进字数字*](#octal_digit) | _
+> *八进制字符组* → [*八进制字符*](#octal_literal_character) [*八进制字符列表*](#octal_literal_characters)可选
+
+> *十进制字面量* → [*十进制数字*](#decimal_digit) [*十进制字符组*](#decimal_literal_characters)可选
+> *十进制数字* → 数值 0 到 9
+> *十进制数字列表* → [*十进制数字*](#decimal_digit) [*十进制数字列表*](#decimal_digits)可选
+> *十进制字符* → [*十进制数字*](#decimal_digit) | _
+> *十进制字符列表* → [*十进制字符*](#decimal_literal_character) [*十进制字符列表*](#decimal_literal_characters)可选
+
+> *十六进制字面量* → **0x** [*十六进制数字*](#hexadecimal_digit) [*十六进制字面量字符列表*](#hexadecimal_literal_characters)可选
+> *十六进制数字* → 数值 0 到 9, 字母 a 到 f, 或 A 到 F
+> *十六进制字符* → [*十六进制数字*](#hexadecimal_digit) | _
+> *十六进制字面量字符列表* → [*十六进制字符*](#hexadecimal_literal_character) [*十六进制字面量字符列表*](#hexadecimal_literal_characters)可选
+
+### 浮点型字面量
+
+浮点型字面量(*floating-point literals*)表示未指定精度浮点数的值。
+
+浮点型字面量默认用十进制表示(无前缀),也可以用十六进制表示(加前缀 `0x`)。
+
+十进制浮点型字面量(*decimal floating-point literals*)由十进制数字串后跟小数部分或指数部分(或两者皆有)组成。十进制小数部分由小数点 `.` 后跟十进制数字串组成。指数部分由大写或小写字母 `e` 为前缀后跟十进制数字串组成,这串数字表示 `e` 之前的数量乘以 10 的几次方。例如:`1.25e2` 表示 `1.25 ⨉ 10^2`,也就是 `125.0`;同样,`1.25e-2` 表示 `1.25 ⨉ 10^-2`,也就是 `0.0125`。
+
+十六进制浮点型字面量(*hexadecimal floating-point literals*)由前缀 `0x` 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字串组成。指数部分由大写或小写字母 `p` 为前缀后跟十进制数字串组成,这串数字表示 `p` 之前的数量乘以 2 的几次方。例如:`0xFp2` 表示 `15 ⨉ 2^2`,也就是 `60`;同样,`0xFp-2` 表示 `15 ⨉ 2^-2`,也就是 `3.75`。
+
+负的浮点型字面量由一元运算符减号 `-` 和浮点型字面量组成,例如 `-42.5`。
+
+浮点型字面量允许使用下划线 `_` 来增强数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,并不会影响字面量的值。
+
+除非特别指定,浮点型字面量的默认推导类型为 Swift 标准库类型中的 `Double`,表示64位浮点数。Swift 标准库也定义了 `Float` 类型,表示32位浮点数。
+
+> 浮点型字面量语法
+> *浮点数字面量* → [*十进制字面量*](#decimal_literal) [*十进制分数*](#decimal_fraction)可选 [*十进制指数*](#decimal_exponent)可选
+> *浮点数字面量* → [*十六进制字面量*](#hexadecimal_literal) [*十六进制分数*](#hexadecimal_fraction)可选 [*十六进制指数*](#hexadecimal_exponent)
+
+> *十进制分数* → **.** [*十进制字面量*](#decimal_literal)
+> *十进制指数* → [*浮点数e*](#floating_point_e) [*正负号*](#sign)可选 [*十进制字面量*](#decimal_literal)
+
+> *十六进制分数* → **.** [*十六进制数字*](#hexadecimal_digit) [*十六进制字面量字符列表*](#hexadecimal_literal_characters)可选
+> *十六进制指数* → [*浮点数p*](#floating_point_p) [*正负号*](#sign)可选 [*十进制字面量*](#decimal_literal)
+
+> *浮点数e* → **e** | **E**
+> *浮点数p* → **p** | **P**
+> *正负号* → **+** | **-**
+
+
+### 字符串型字面量
+
+字符串型字面量(*string literal*)由被包在双引号中的一串字符组成,形式如下:
+
+```
+"characters"
+```
+
+字符串型字面量中不能包含未转义的双引号 (`"`)、未转义的反斜线(`\`)、回车符(*carriage return*)或换行符(*line feed*)。
+
+可以在字符串字面量中使用的转义特殊符号如下:
+
+* 空字符(Null Character)`\0`
+* 反斜线(Backslash)`\\`
+* 水平制表符(Horizontal Tab)`\t`
+* 换行符(Line Feed)`\n`
+* 回车符(Carriage Return)`\r`
+* 双引号(Double Quote)`\"`
+* 单引号(Single Quote)`\'`
+* Unicode标量 `\u{n}`,n为一到八位的十六进制数字
+
+字符串字面量允许在反斜杠小括号 `\()` 中插入表达式的值。插入表达式(*interpolated expression*)不能包含未转义的双引号 `"`、未转义的反斜线 `\`、回车符或者换行符。表达式结果的类型必须在 *String* 类中有对应的初始化方法。
+
+例如,以下所有字符串字面量的值都是相同的:
+
+```
+"1 2 3"
+"1 2 \(3)"
+"1 2 \(1 + 2)"
+let x = 3; "1 2 \(x)"
+```
+
+字符串字面量的默认推导类型为 `String`。组成字符串的字符默认推导类型为 `Character`。更多有关 `String` 和 `Character` 的信息请参照 [字符串和字符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_368)。
+
+> 字符型字面量语法
+> *字符串字面量* → **"** [*引用文本*](#quoted_text)可选 **"**
+
+> *引用文本* → [*引用文本条目*](#quoted_text_item) [*引用文本*](#quoted_text) 可选
+> *引用文本条目* → [*转义字符*](#escaped_character)
+> *引用文本条目* → **\(** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID383) **)**
+> *引用文本条目* → **除了", \, U+000A, 或者 U+000D的所有Unicode的字符**
+> *转义字符* → **\0** | **\\** | **\t** | **\n** | **\r** | **\"** | **\'**
+> *转义字符* → **\u {** [*unicode标量数字*](#unicode_scalar_digits) **}**
+> *unicode标量数字* → 一到八位的十六进制数字
+
+
+## 运算符
+
+Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基础运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-XID_70) 和 [高级运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_28) 中进行了阐述。这一小节将描述哪些字符能用于自定义运算符。
+
+自定义运算符可以由以下其中之一的 ASCII 字符 `/`、`=`、 `-`、`+`、`!`、`*`、`%`、`<`、`>`、`&`、`|`、`^`、`?` 以及 `~`, 或者后面语法中规定的任一个 Unicode 字符开始。在第一个字符之后,允许使用组合型 Unicode 字符。也可以使用两个或者多个的点号来自定义运算符(比如, `....`)。虽然可以自定义包含问号`?`的运算符,但是这个运算符不能只包含单独的一个问号。
+
+ 注意:
+ 以下这些标记 =, ->, //, /*, */, ., <(前缀运算符), &, and ?, ?(中缀运算符), >(后缀运算符), ! 以及 ? 是被系统保留的。这些标记不能被重载,也不能用于自定义操作符。
+
+运算符两侧的空白被用来区分该运算符是否为前缀运算符(*prefix operator*)、后缀运算符(*postfix operator*)或二元运算符(*binary operator*)。规则总结如下:
+
+* 如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:`a+b` 和 `a + b` 中的运算符 `+` 被看作二元运算符。
+* 如果运算符只有左侧空白,将被看作前缀一元运算符。例如 `a ++b` 中的 `++` 被看作前缀一元运算符。
+* 如果运算符只有右侧空白,将被看作后缀一元运算符。例如 `a++ b` 中的 `++` 被看作后缀一元运算符。
+* 如果运算符左侧没有空白并紧跟 `.`,将被看作后缀一元运算符。例如 `a++.b` 中的 `++` 被看作后缀一元运算符(即上式被视为 `a++ .b` 而非 `a ++ .b`)。
+
+鉴于这些规则,运算符前的字符 `(`、`[` 和 `{` ;运算符后的字符 `)`、`]` 和 `}` 以及字符 `,`、`;` 和 `:` 都被视为空白。
+
+以上规则需注意一点,如果预定义运算符 `!` 或 `?` 左侧没有空白,则不管右侧是否有空白都将被看作后缀运算符。如果将 `?` 用作可选链(*optional-chaining*)操作符,左侧必须无空白。如果用于条件运算符 `? :`,必须两侧都有空白。
+
+在某些特定的构造中 ,以 `<` 或 `>` 开头的运算符会被分离成两个或多个标记,剩余部分以同样的方式会被再次分离。因此,在 `Dictionary`introduced=version number`
这里的`version number`由一个正的十进制整数或浮点数构成。 +- `iOS` +- `iOSApplicationExtension` +- `OSX` +- `OSXApplicationExtension` +- `watchOS` -- `deprecated`参数表示:特定的平台上,该声明被建议弃用的第一个版本。格式如下: +当然,你也可以用一个星号(*)来表示,该声明在上面提到的所有平台上都是有效的。 + +剩下的参数,可以以任何顺序出现,并且可以添加关于声明生命周期的附加信息,包括重要的里程碑。 + +- `unavailable`参数表示:该声明在特定的平台上是无效的 + +- `introduced`参数表示:该声明第一次被引入时所在平台的版本。格式如下: +
`introduced=version number`
这里的`version number`由一个正的十进制整数或浮点数构成。 + +- `deprecated`参数表示:该声明第一次被建议弃用时所在平台的版本。格式如下:
`deprecated=version number`
这里的`version number`由一个正的十进制整数或浮点数构成。 -- `obsoleted`参数表示:特定的平台上,该声明被弃用的第一个版本。格式如下: -
`deprecated=version number`
这里的`version number`由一个正的十进制整数或浮点数构成。 +- `obsoleted`参数表示:该声明第一次被弃用时所在平台的版本。当一个声明被弃用时,它就从此平台中被移除,不能再被使用。格式如下: +
`obsoleted=version number`
这里的`version number`由一个正的十进制整数或浮点数构成。 -- `message`参数用来提供文本信息,并在因使用建议弃用或者被弃用的声明而遇到警告或错误时,由编译器抛出。格式如下: +- `message`参数用来提供文本信息。当使用建议弃用或者被弃用的声明时,编译器会抛出错误或警告信息。格式如下:
`message=message`
这里的`message`由一个字符串文字构成。 -- `renamed`参数用来提供文本信息,用以表示被重命名的声明的新名字。当使用这个重命名的声明遇到错误时,该新名字会被编译器显示出来。格式如下: +- `renamed`参数用来提供文本信息,用以表示被重命名的声明的新名字。当使用这个重命名的声明遇到错误时,编译器会显示出该新名字。格式如下:
`renamed=new name`
这里的`new name`由一个字符串文字构成。 -你可以将`renamed`参数和`unavailable`参数以及类型别名声明组合使用,以向用户表示:在你的代码中,一个声明已经被重命名。当一个声明的名字在一个框架或者库的不同发布版本间发生变化时,这会相当管用。 +你可以将`renamed`参数和`unavailable`参数以及类型别名声明组合使用,以向用户表示:在你的代码中,一个声明已经被重命名。当一个声明的名字在一个框架或者库的不同发布版本间发生变化时,这会相当有用。 ```swift // First release @@ -58,50 +72,34 @@ protocol MyRenamedProtocol { // protocol definition } -@availability(*, unavailable, renamed="MyRenamedProtocol") +@available(*, unavailable, renamed="MyRenamedProtocol") typealias MyProtocol = MyRenamedProtocol ``` -你可以在一个单独的声明上使用多个`availability`特性,以详细说明该声明在不同平台上的有效性。编译器只有在当前的目标平台和`availability`特性中指定的平台匹配时,才会使用`availability`特性 +你可以在一个单独的声明上使用多个`available`特性,以详细说明该声明在不同平台上的有效性。编译器只有在当前的目标平台和`available`特性中指定的平台匹配时,才会使用`available`特性 -`autoclosure` +如果`available`特性除了平台名称参数外,只指定了一个`introduced `参数,那么可以使用以下简写语法代替: -这个属性通过把表达式自动封装成不带参数的闭包来延迟表达式的计算。这个属性使用在函数参数声明或者不带参数但是返回表达式类型的方法类型上。含有```autoclosure```属性的声明同时也具有```noescape```的特性,除非传递一个可选的参数属性```escaping```,请看[函数类型](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID449)。 +@available(`platform name` `version number`, *) -`noescape` - -在函数或者方法声明上使用该属性表示参数将不会被存储用作后续的计算,其用来确保不会超出函数调用的声明周期。使用```noescape```声明属性的函数类型不需要显式的使用```self```,对于其属性或者方法来说。 - -`noreturn` - -该特性用于修饰函数或方法声明,表明该函数或方法的对应类型,`T`,是`@noreturn T`。你可以用这个特性修饰函数或方法的类型,这样一来,函数或方法就不会返回到它的调用者中去。 - -对于一个没有用`noreturn`特性标记的函数或方法,你可以将它重写(override)为用该特性标记的。相反,对于一个已经用`noreturn`特性标记的函数或方法,你则不可以将它重写为没使用该特性标记的。相同的规则试用于当你在一个comforming类型中实现一个协议方法时。 - -`NSApplicationMain` -在类上使用该属性表示该类是应用程序委托类,使用该属性与调用```NSApplicationMain```函数并且把该类的名字作为委托类的名字传递给函数的效果相同。 - -如果你不想使用这个属性,可以提供一个```main.swift```文件,并且提供一个```main```函数去调用```NSApplicationMain```函数。比如,如果你的应用程序使用一个派生于```NSApplication```的自定义子类作为主要类,你可以调用```NSApplicationMain```函数而不是使用该属性。 - - -`NSCopying` - -该特性用于修饰一个类的存储型变量属性。该特性将使属性的setter与属性值的一个副本合成,由`copyWithZone`方法返回,而不是属性本身的值。该属性的类型必需遵循`NSCopying`协议。 - -`NSCopying`特性的行为与Objective-C中的`copy`特性相似。 - -`NSManaged` - -该特性用于修饰`NSManagedObject`子类中的存储型变量属性,表明属性的存储和实现由Core Data在运行时基于相关实体描述动态提供。 +`available`特性的简写语法可以简明地表达出多个平台的可用性。尽管这两种形式在功能上是相同的,但请尽可能地使用简明语法形式。 +```swift +@available(iOS 8.0, OSX 10.10, *) +class MyClass { + // class definition +} +``` `objc` -该特性用于修饰任意可以在Objective-C中表示的声明,比如,非嵌套类,协议,类和协议中的属性和方法(包含getter和setter),初始化器,析构器,以及下标。`objc`特性告诉编译器该声明可以在Objective-C代码中使用。 +该特性用于修饰任何可以在Objective-C中表示的声明。比如,非嵌套类、协议、非泛型枚举(仅限整型值类型)、类和协议的属性和方法(包括`getter`和`setter`)、构造器、析构器以及下标。`objc`特性告诉编译器这个声明可以在Objective-C代码中使用。 -如果你将`objc`特性应用于一个类或协议,它也会隐式地应用于那个类或协议的成员。对于标记了`objc`特性的类,编译器会隐式地为它的子类添加`objc`特性。标记了`objc`特性的协议不能继承自没有标记`objc`的协议。 +如果你将`objc`特性应用于一个类或协议,它也会隐式地应用于那个类的成员或协议。对于标记了`objc`特性的类,编译器会隐式地为它的子类添加`objc`特性。标记了`objc`特性的协议不能继承没有标记`objc`的协议。 -`objc`特性有一个可选的参数,由标记符组成。当你想把`objc`所修饰的实体以一个不同的名字暴露给Objective-C,你就可以使用这个特性参数。你可以使用这个参数来命名类,协议,方法,getters,setters,以及初始化器。下面的例子把`ExampleClass`中`enabled`属性的getter暴露给Objective-C,名字是`isEnabled`,而不是它原来的属性名。 +如果你将`objc`特性应用于枚举,每一个枚举的`case`都会以枚举名称和`case`名称组合的方式暴露在Objective-C代码中。例如:一个名为`Venus`的`case`在`Planet`枚举中,这个`case`暴露在Objective-C代码中时叫做`PlanetVenus`。 + +`objc`特性有一个可选的参数,由标记符组成。当你想把`objc`所修饰的实体以一个不同的名字暴露给Objective-C时,你就可以使用这个特性参数。你可以使用这个参数来命名类,协议,方法,getters,setters,以及构造器。下面的例子把`ExampleClass`中`enabled`属性的getter暴露给Objective-C,名字是`isEnabled`,而不是它原来的属性名。 ```swift @objc @@ -114,17 +112,64 @@ class ExampleClass { } ``` -`optional` +`noescape` -用该特性修饰协议的属性,方法或下标成员,表示实现这些成员并不需要一致性类型(conforming type)。 +在函数或者方法声明上使用该特性,它表示参数将不会被存储用作后续的计算,其用来确保不会超出函数调用的生命周期。对于其属性或方法来说,使用`noescape`声明属性的函数类型不需要显式的使用`self.`。 -你只能用`optional`特性修饰那些标记了`objc`特性的协议。因此,只有类类型可以adopt和comform to那些包含可选成员需求的协议。更多关于如何使用`optional`特性以及如何访问可选协议成员的指导,例如,当你不确定一个conforming类型是否实现了它们,请见:[可选协议需求]()。 +`nonobjc` -`required` +该特性用于方法、属性、下标、或构造器的声明,这些声明本是可以在Objective-C代码中表示的。使用`nonobjc`特性告诉编译器这个声明不能在Objective-C代码中使用。 -用该特性修饰一个类的指定或便利初始化器,表示该类的所有子类都必需实现该初始化器。 +可以使用`nonobjc`特性解决标有`objc`的类中桥接方法的循环问题,该特性还允许标有`objc`的类的构造器和方法进行重载(overload)。 -加了该特性的指定初始化器必需显式地实现,而便利初始化器既可显式地实现,也可以在子类实现了超类所有指定初始化器后继承而来(或者当子类使用便利初始化器重写了指定初始化器)。 +标有`nonobjc`特性的方法不能重写(override)一个标有`objc`特性的方法。然而,标有`objc`特性的方法可以重写标有`nonobjc`特性的方法。同样,标有`nonobjc`特性的方法不能满足一个需要标有`@objc`特性的方法的协议。 + +`noreturn` + +该特性用于修饰函数或方法声明,表明该函数或方法的对应类型,`T`,是`@noreturn T`。你可以用这个特性修饰函数或方法的类型,这样一来,函数或方法就不会返回到它的调用者中去。 + +对于一个没有用`noreturn`特性标记的函数或方法,你可以将它重写为用该特性标记的。相反,对于一个已经用`noreturn`特性标记的函数或方法,你则不可以将它重写为没使用该特性标记的。当你在一个comforming类型中实现一个协议方法时,该规则同样适用。 + +`NSApplicationMain` + +在类上使用该特性表示该类是应用程序委托类,使用该特性与调用`NSApplicationMain(_:_:)`函数并且把该类的名字作为委托类的名字传递给函数的效果相同。 + +如果你不想使用这个特性,可以提供一个`main.swift`文件,并且提供一个`main`函数去调用`NSApplicationMain(_:_:)`函数。比如,如果你的应用程序使用一个派生于`NSApplication`的自定义子类作为主要类,你可以调用`NSApplicationMain`函数而不是使用该特性。 + +`NSCopying` + +该特性用于修饰一个类的存储型变量属性。该特性将使属性的setter与属性值的一个副本合成,这个值由`copyWithZone(_:)`方法返回,而不是属性本身的值。该属性的类型必需遵循`NSCopying`协议。 + +`NSCopying`特性的原理与Objective-C中的`copy`特性相似。 + +`NSManaged` + +该特性用于修饰`NSManagedObject`子类中的存储型变量属性,表明属性的存储和实现由Core Data在运行时基于相关实体描述动态提供。 + +`testable` + +该特性用于`import`声明可以测试的编译模块,它能访问任何标有`internal`权限标识符的实体,这和将它声明为`public`权限标识符有同样的效果。 + +`UIApplicationMain` + +在类上使用该特性表示该类是应用程序委托类,使用该特性与调用`UIApplicationMain(_:_:)`函数并且把该类的名字作为委托类的名字传递给函数的效果相同。 + +如果你不想使用这个特性,可以提供一个`main.swift`文件,并且提供一个`main`函数去调用`UIApplicationMain(_:_:)`函数。比如,如果你的应用程序使用一个派生于`UIApplication`的自定义子类作为主要类,你可以调用`UIApplicationMain`函数而不是使用该特性。 + +`warn_unused_result` + +该特性应用于方法或函数声明,当方法或函数被调用,但其结果未被使用时,该特性会让编译器会产生警告。 + +你可以使用这个特性提供一个警告信息,这个警告信息是关于不正确地使用未变异的方法的,这个方法也有一个对应的变异方法。 + +`warn_unused_result`有下面两个可选的参数。 + +- `message`参数用来提供警告信息,并在因当方法或函数被调用,但其结果未被使用时,显示警告信息。格式如下: +
`message=message`
这里的`message`由一个字符串文字构成。 + +- `mutable_variant`参数用于提供变异方法的名称,如果未变异方法以一个可变的值被调用而且其结果并未被使用时,应该使用此变异方法。格式如下(方法名有字符串构成):
`mutable_variant=method name`
+
+比如,Swift标准库提供了变异方法`sortInPlace()`和未变异方法`sort()`集合,它们的元素生成器符合`Comparable`协议。如果你调用了`sort()`方法,而没有使用它的结果,很有可能,你打算使用变异方法`sortInPlace()`替代。
### Interface Builder使用的声明特性
@@ -137,22 +182,36 @@ Interface Builder特性是Interface Builder用来与Xcode同步的声明特性
类型特性只能用于修饰类型。然而,你也可以用`noreturn`特性去修饰函数或方法声明。
-`auto_closure`
+`convention`
-这个特性通过自动地将表达式封闭到一个无参数闭包中来延迟表达式的求值。使用该特性修饰无参的函数或方法类型,返回表达式的类型。一个如何使用`auto_closure`特性的例子,见[函数类型]()
+该特性用于函数的类型,它指出函数调用的约定。
+
+`convention`特性有下面几个可选的参数。
+
+- `swift`参数用于表明一个Swift函数引用。这是Swift中标准的函数值调用约定。
+
+- `block`参数用于表明一个Objective-C兼容的块引用。函数值表示为一个块对象的引用,这是一个`id-`兼容的Objective-C对象,对象中嵌入了调用函数。调用函数使用C的调用约定。
+
+- `c`参数用于表明一个C函数引用。函数值没有上下文,这个函数也使用C的调用约定。
+
+使用C函数调用约定的函数也可用作使用Objective-C块调用约定的函数,同时使用Objective-C块调用约定的函数也可用作使用Swift函数调用约定的函数。然而,只有非泛型的全局函数和本地函数或者不使用任何本地变量的闭包可以被用作使用C函数调用约定的函数。
`noreturn`
该特性用于修饰函数或方法的类型,表明该函数或方法不会返回到它的调用者中去。你也可以用它标记函数或方法的声明,表示函数或方法的相应类型,`T`,是`@noreturn T`。
-> 特性语法
-> *特性* → **@** [*特性名*](..\chapter3\06_Attributes.html#attribute_name) [*特性参数子句*](..\chapter3\06_Attributes.html#attribute_argument_clause) _可选_
-> *特性名* → [*标识符*](LexicalStructure.html#identifier)
-> *特性参数子句* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)**
-> *特性(Attributes)列表* → [*特色*](..\chapter3\06_Attributes.html#attribute) [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_
-> *平衡令牌列表* → [*平衡令牌*](..\chapter3\06_Attributes.html#balanced_token) [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_
-> *平衡令牌* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)**
-> *平衡令牌* → **[** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **]**
-> *平衡令牌* → **{** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **}**
+> 特性语法
+> *特性* → **@** [*特性名*](#attribute_name) [*特性参数子句*](#attribute_argument_clause) _可选_
+> *特性名* → [*标识符*](02_Lexical_Structure.html#identifiers)
+> *特性参数子句* → **(** [*平衡令牌列表*](#balanced_tokens) _可选_ **)**
+> *特性(Attributes)列表* → [*特色*](#attribute) [*特性(Attributes)列表*](#attributes) _可选_
+> *平衡令牌列表* → [*平衡令牌*](#balanced_token) [*平衡令牌列表*](#balanced_tokens) _可选_
+> *平衡令牌* → **(** [*平衡令牌列表*](#balanced_tokens) _可选_ **)**
+> *平衡令牌* → **[** [*平衡令牌列表*](#balanced_tokens) _可选_ **]**
+> *平衡令牌* → **{** [*平衡令牌列表*](#balanced_tokens) _可选_ **}**
> *平衡令牌* → **任意标识符, 关键字, 字面量或运算符**
> *平衡令牌* → **任意标点除了(, ), [, ], {, 或 }**
+
+
+
+
diff --git a/source/chapter3/07_Patterns.md b/source/chapter3/07_Patterns.md
index 3448a392..fb93956d 100755
--- a/source/chapter3/07_Patterns.md
+++ b/source/chapter3/07_Patterns.md
@@ -1,4 +1,4 @@
-> 翻译:[honghaoz](https://github.com/honghaoz)
+> 翻译:[honghaoz](https://github.com/honghaoz), [ray16897188](https://github.com/ray16897188)
> 校对:[numbbbbb](https://github.com/numbbbbb), [stanzhai](https://github.com/stanzhai)
# 模式(Patterns)
@@ -11,28 +11,32 @@
- [值绑定模式(Value-Binding Pattern)](#value-binding_pattern)
- [元组模式(Tuple Pattern)](#tuple_pattern)
- [枚举用例模式(Enumeration Case Pattern)](#enumeration_case_pattern)
-- [类型转换模式(Type-Casting Patterns)](#type-casting_patterns)
+- [可选模式(Optional Pattern)](#optional_pattern)
+- [类型转换模式(Type-Casting Pattern)](#type-casting_pattern)
- [表达式模式(Expression Pattern)](#expression_pattern)
-模式(pattern)代表了单个值或者复合值的结构。例如,元组`(1, 2)`的结构是逗号分隔的,包含两个元素的列表。因为模式代表一种值的结构,而不是特定的某个值,你可以把模式和各种同类型的值匹配起来。比如,`(x, y)`可以匹配元组`(1, 2)`,以及任何含两个元素的元组。除了将模式与一个值匹配外,你可以从合成值中提取出部分或全部,然后分别把各个部分和一个常量或变量绑定起来。
+模式(pattern)代表了单个值或者复合值的结构。例如,元组`(1, 2)`的结构是逗号分隔的,包含两个元素的列表。因为模式代表一种值的结构,而不是特定的某个值,你可以把模式和各种同类型的值匹配起来。比如,`(x, y)`可以匹配元组`(1, 2)`,以及任何含两个元素的元组。除了将模式与一个值匹配外,你可以从复合值中提取出部分或全部,然后分别把各个部分和一个常量或变量绑定起来。
-在Swift中,模式出现在变量和常量的声明(在它们的左侧),`for-in`语句和`switch`语句(在它们的case标签)中。尽管任何模式都可以出现在`switch`语句的case标签中,但在其他情况下,只有通配符模式(wildcard pattern),标识符模式(identifier pattern)和包含这两种模式的模式才能出现。
+swift语言中模式有2个基本的分类:一类能成功和任何值的类型相匹配,另一类在运行时(runtime)和某特定值匹配时可能会失败。
-你可以为通配符模式(wildcard pattern),标识符模式(identifier pattern)和元组模式(tuple pattern)指定类型注释,用来限制这种模式只匹配某种类型的值。
+第一类模式用于解构简单变量,常量和可选绑定中的值。此类模式包括通配符模式(wildcard patterns),标识符模式(identifier patterns),以及任何包含了它们的值绑定模式(value binding patterns)或者元祖模式(tuple patterns)。你可以为这类模式指定一个类型标注(type annotation)从而限制它们只能匹配某种特定类型的值。
+
+第二类模式用于全模式匹配,这种情况下你用来相比较的值在运行时可能还不存在。此类模式包括枚举用例模式(enumeration case patterns),可选模式(optional patterns),表达式模式(expression patterns)和类型转换模式(type-casting patterns)。你在`switch`语句的case标签中,`do`语句的`catch`从句中,或者在`if, while, guard`和`for-in`语句的case条件句中使用这类模式。
> 模式(Patterns) 语法
-> *模式* → [*通配符模式*](..\chapter3\07_Patterns.html#wildcard_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotation) _可选_
-> *模式* → [*标识符模式*](..\chapter3\07_Patterns.html#identifier_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotati(Value Binding)on) _可选_
+> *模式* → [*通配符模式*](..\chapter3\07_Patterns.html#wildcard_pattern) [*类型标注*](..\chapter3\03_Types.html#type_annotation) _可选_
+> *模式* → [*标识符模式*](..\chapter3\07_Patterns.html#identifier_pattern) [*类型标注*](..\chapter3\03_Types.html#type_annotati(Value Binding)on) _可选_
> *模式* → [*值绑定模式*](..\chapter3\07_Patterns.html#value_binding_pattern)
-> *模式* → [*元组模式*](..\chapter3\07_Patterns.html#tuple_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotation) _可选_
-> *模式* → [*enum-case-pattern*](..\chapter3\07_Patterns.html#enum_case_pattern)
-> *模式* → [*type-casting-pattern*](..\chapter3\07_Patterns.html#type_casting_pattern)
+> *模式* → [*元组模式*](..\chapter3\07_Patterns.html#tuple_pattern) [*类型标注*](..\chapter3\03_Types.html#type_annotation) _可选_
+> *模式* → [*枚举用例模式*](..\chapter3\07_Patterns.html#enum_case_pattern)
+> *模式* → [*可选模式*](..\chapter3\07_Patterns.html#optional_pattern)
+> *模式* → [*类型转换模式*](..\chapter3\07_Patterns.html#type_casting_pattern)
> *模式* → [*表达式模式*](..\chapter3\07_Patterns.html#expression_pattern)
## 通配符模式(Wildcard Pattern)
-通配符模式匹配并忽略任何值,包含一个下划线(_)。当你不关心被匹配的值时,可以使用此模式。例如,下面这段代码进行了`1...3`的循环,并忽略了每次循环的值:
+通配符模式由一个下划线(_)构成,且匹配并忽略任何值。当你不在乎被匹配的值时可以使用该模式。例如,下面这段代码在闭区间`1...3`中循环,每次循环时忽略该区间内的当前值:
```swift
for _ in 1...3 {
@@ -46,7 +50,7 @@ for _ in 1...3 {
## 标识符模式(Identifier Pattern)
-标识符模式匹配任何值,并将匹配的值和一个变量或常量绑定起来。例如,在下面的常量申明中,`someValue`是一个标识符模式,匹配了类型是`Int`的`42`。
+标识符模式匹配任何值,并将匹配的值和一个变量或常量绑定起来。例如,在下面的常量声明中,`someValue`是一个标识符模式,匹配了类型是`Int`的`42`。
```swift
let someValue = 42
@@ -54,7 +58,7 @@ let someValue = 42
当匹配成功时,`42`被绑定(赋值)给常量`someValue`。
-当一个变量或常量申明的左边是标识符模式时,此时,标识符模式是隐式的值绑定模式(value-binding pattern)。
+如果一个变量或常量声明的左边的模式是一个标识符模式,那么这个标识符模式是一个隐式的值绑定模式(value-binding pattern)。
> 标识符模式语法
> *标识符模式* → [*标识符*](LexicalStructure.html#identifier)
@@ -62,21 +66,21 @@ let someValue = 42
## 值绑定模式(Value-Binding Pattern)
-值绑定模式绑定匹配的值到一个变量或常量。当绑定匹配值给常量时,用关键字`let`,绑定给变量时,用关键字`var`。
+值绑定模式把匹配到的值绑定给一个变量或常量名。把绑定匹配到的值绑定给常量时,用关键字`let`,绑定给变量时,用关键字`var`。
-标识符模式包含在值绑定模式中,绑定新的变量或常量到匹配的值。例如,你可以分解一个元组的元素,并把每个元素绑定到相应的标识符模式中。
+在值绑定模式中的标识符模式会把新命名的变量或常量与匹配值做绑定。例如,你可以拆开一个元组的元素,然后把每个元素绑定到其相应一个的标识符模式中。
```swift
let point = (3, 2)
switch point {
// Bind x and y to the elements of point.
case let (x, y):
- println("The point is at (\(x), \(y)).")
+ print("The point is at (\(x), \(y)).")
}
// 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)
@@ -84,11 +88,11 @@ case let (x, y):
## 元组模式(Tuple Pattern)
-元组模式是逗号分隔的列表,包含一个或多个模式,并包含在一对圆括号中。元组模式匹配相应元组类型的值。
+元组模式是逗号分隔的,有零个或多个模式的列表,并被一对圆括号括起来。元组模式匹配相应元组类型的值。
-你可以使用类型注释来限制一个元组模式来匹配某种元组类型。例如,在常量申明`let (x, y): (Int, Int) = (1, 2)`中的元组模式`(x, y): (Int, Int)`,只匹配两个元素都是`Int`这种类型的元组。如果仅需要限制一个元组模式中的某几个元素,只需要直接对这几个元素提供类型注释即可。例如,在`let (x: String, y)`中的元组模式,只要某个元组类型是包含两个元素,且第一个元素类型是`String`,则被匹配。
+你可以使用类型标注去限制一个元组模式能匹配哪些种元组类型。例如,在常量声明`let (x, y): (Int, Int) = (1, 2)`中的元组模式`(x, y): (Int, Int)`只匹配两个元素都是`Int`这种类型的元组。如果仅需要限制一个元组模式中的某几个元素,只需要直接对这几个元素提供类型标注即可。例如,在`let (x: String, y)`中的元组模式可以和任何有两个元素,且第一个元素类型是`String`的元组类型匹配。
-当元组模式被用在`for-in`语句或者变量或常量申明时,它可以包含通配符模式,标识符模式或者其他包含这两种模式的模式。例如,下面这段代码是不正确的,因为`(x, 0)`中的元素`0`是一个表达式模式:
+当元组模式被用在`for-in`语句或者变量或常量声明时,它仅可以包含通配符模式,标识符模式,可选模式或者其他包含这些模式的元祖模式。比如下面这段代码就不正确,因为`(x, 0)`中的元素`0`是一个表达式模式:
```swift
let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)]
@@ -98,7 +102,7 @@ for (x, 0) in points {
}
```
-对于只包含一个元素的元组,括号是不起作用的。模式匹配那个单个元素的类型。例如,下面是等效的:
+对于只包含一个元素的元组,括号是不起作用的。模式只匹配这个单个元素的类型。举例来说,下面3条语句是等效的:
```swift
let a = 2 // a: Int = 2
@@ -114,24 +118,59 @@ let (a): Int = 2 // a: Int = 2
## 枚举用例模式(Enumeration Case Pattern)
-枚举用例模式匹配现有的枚举类型的某种用例。枚举用例模式仅在`switch`语句中的`case`标签中出现。
+一个枚举用例模式匹配现有的某个枚举类型的某个用例(case)。枚举用例模式出现在`switch`语句中的case标签中,以及`if`,`while`,`guard`和`for-in`语句的case条件中。
如果你准备匹配的枚举用例有任何关联的值,则相应的枚举用例模式必须指定一个包含每个关联值元素的元组模式。关于使用`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) _可选_
+
+## 可选模式(Optional Pattern)
+
+可选模式与封装在一个`Optional(T)`或者一个`ExplicitlyUnwrappedOptional(T)`枚举中的`Some(T)`用例相匹配。可选模式由一个标识符模式和紧随其后的一个问号组成,在某些情况下表现为枚举用例模式。
+
+由于可选模式是`optional`和`ImplicitlyUnwrappedOptional`枚举用例模式的语法糖(syntactic sugar),下面的2种写法是一样的:
+
+```swift
+let someOptional: Int? = 42
+// Match using an enumeration case pattern
+if case .Some(let x) = someOptional {
+ print(x)
+}
+
+// Match using an optional pattern
+if case let x? = someOptional {
+ print(x)
+}
+```
+如果一个数组的元素是可选类型,可选模式为`for-in`语句提供了一种在该数组中迭代的简便方式,只为数组中的非空`non-nil`元素执行循环体。
+
+```swift
+let arrayOfOptionalInts: [Int?] = [nil, 2, 3, nil, 5]
+// Match only non-nil values
+for case let number? in arrayOfOptinalInts {
+ print("Found a \(number)")
+}
+//Found a 2
+//Found a 3
+//Found a 5
+
+```
+> 可选模式语法
+> *可选模式* → [*标识符模式*](..\chapter3\03_Types.html#type_identifier) ?
+
## 类型转换模式(Type-Casting Patterns)
-有两种类型转换模式,`is`模式和`as`模式。这两种模式均只出现在`switch`语句中的`case`标签中。`is`模式和`as`模式有以下形式:
+有两种类型转换模式,`is`模式和`as`模式。这两种模式只出现在`switch`语句中的case标签中。`is`模式和`as`模式有以下形式:
> is `type`
> `pattern` as `type`
-`is`模式匹配一个值,如果这个值的类型在运行时(runtime)和`is`模式右边的指定类型(或者那个类型的子类)是一致的。`is`模式和`is`操作符一样,它们都进行类型转换,但是抛弃了返回的类型。
+`is`模式仅当一个值的类型在运行时(runtime)和`is`模式右边的指定类型一致 - 或者是该类型的子类 - 的情况下,才会匹配这个值。`is`模式和`is`操作符有相似表现,它们都进行类型转换,却舍弃返回的类型。
-`as`模式匹配一个值,如果这个值的类型在运行时(runtime)和`as`模式右边的指定类型(或者那个类型的子类)是一致的。一旦匹配成功,匹配的值的类型被转换成`as`模式左边指定的模式。
+`as`模式仅当一个值的类型在运行时(runtime)和`as`模式右边的指定类型一致 - 或者是该类型的子类 - 的情况下,才会匹配这个值。如果匹配成功,被匹配的值的类型被转换成`as`模式左边指定的模式。
关于使用`switch`语句来匹配`is`模式和`as`模式值的例子,请参阅`Type Casting for Any and AnyObject`。
@@ -143,24 +182,24 @@ let (a): Int = 2 // a: Int = 2
## 表达式模式(Expression Pattern)
-表达式模式代表了一个表达式的值。这个模式只出现在`switch`语句中的`case`标签中。
+一个表达式模式代表了一个表达式的值。表达式模式只出现在`switch`语句中的`case`标签中。
-由表达式模式所代表的表达式用Swift标准库中的`~=`操作符与输入表达式的值进行比较。如果`~=`操作符返回`true`,则匹配成功。默认情况下,`~=`操作符使用`==`操作符来比较两个相同类型的值。它也可以匹配一个整数值与一个`Range`对象中的整数范围,正如下面这个例子所示:
+由表达式模式所代表的表达式与使用了Swift标准库中`~=`操作符的输入表达式的值进行比较。如果`~=`操作符返回`true`,则匹配成功。默认情况下,`~=`操作符使用`==`操作符来比较两个相同类型的值。它也可以将一个整型数值与一个`Range`对象中的一段整数区间做匹配,正如下面这个例子所示:
```swift
let point = (1, 2)
switch point {
case (0, 0):
- println("(0, 0) is at the origin.")
+ print("(0, 0) is at the origin.")
case (-2...2, -2...2):
- println("(\(point.0), \(point.1)) is near the origin.")
+ print("(\(point.0), \(point.1)) is near the origin.")
default:
- println("The point is at (\(point.0), \(point.1)).")
+ print("The point is at (\(point.0), \(point.1)).")
}
// prints "(1, 2) is near the origin.”
```
-你可以重载`~=`操作符来提供自定义的表达式行为。例如,你可以重写上面的例子,以实现用字符串表达的点来比较`point`表达式。
+你可以重载`~=`操作符来提供自定义的表达式匹配行为。比如你可以重写上面的例子,拿`point`表达式去比较字符串形式的点。
```swift
// Overload the ~= operator to match a string with an integer
@@ -169,14 +208,12 @@ func ~=(pattern: String, value: Int) -> Bool {
}
switch point {
case ("0", "0"):
- println("(0, 0) is at the origin.")
-case ("-2...2", "-2...2"):
- println("(\(point.0), \(point.1)) is near the origin.")
+ print("(0, 0) is at the origin.")
default:
- println("The point is at (\(point.0), \(point.1)).")
+ print("The point is at (\(point.0), \(point.1)).")
}
// prints "(1, 2) is near the origin.”
```
> 表达式模式语法
-> *表达式模式* → [*表达式*](..\chapter3\04_Expressions.html#expression)
\ No newline at end of file
+> *表达式模式* → [*表达式*](..\chapter3\04_Expressions.html#expression)
diff --git a/source/chapter3/08_Generic_Parameters_and_Arguments.md b/source/chapter3/08_Generic_Parameters_and_Arguments.md
index 06a078b0..9bb891a4 100755
--- a/source/chapter3/08_Generic_Parameters_and_Arguments.md
+++ b/source/chapter3/08_Generic_Parameters_and_Arguments.md
@@ -1,5 +1,5 @@
> 翻译:[fd5788](https://github.com/fd5788)
-> 校对:[yankuangshi](https://github.com/yankuangshi), [stanzhai](https://github.com/stanzhai)
+> 校对:[yankuangshi](https://github.com/yankuangshi), [stanzhai](https://github.com/stanzhai), [wardenNScaiyi](https:github.com/wardenNScaiyi)
# 泛型参数
---------
@@ -9,28 +9,29 @@
- [泛型形参子句](#generic_parameter)
- [泛型实参子句](#generic_argument)
-本节涉及泛型类型、泛型函数以及泛型构造器的参数,包括形参和实参。声明泛型类型、函数或构造器时,须指定相应的类型参数。类型参数相当于一个占位符,当实例化泛型类型、调用泛型函数或泛型构造器时,就用具体的类型实参替代之。
+本节涉及泛型类型、泛型函数以及泛型初始化器(**initializer**)的参数,包括形参和实参。声明泛型类型、函数或初始化器时,须指定相应的类型参数。类型参数相当于一个占位符,当实例化泛型类型、调用泛型函数或泛型初始化器时,就用具体的类型实参替代之。
关于 Swift 语言的泛型概述,见[泛型](../charpter2/22_Generics.md)(第二部分第22章)。
## 泛型形参子句
-泛型形参子句指定泛型类型或函数的类型形参,以及这些参数的关联约束和要求。泛型形参子句用尖括号(<>)包住,并且有以下两种形式:
+泛型形参子句指定泛型类型或函数的类型形参,以及这些参数的关联约束和关联类型要求(**requirement**)。泛型形参子句用尖括号(<>)包住,并且有以下两种形式:
-> <`generic parameter list`>
-> <`generic parameter list` where `requirements`>
+> <`泛型形参列表`>
+> <`泛型形参列表` where `关联类型要求`>
-泛型形参列表中泛型形参用逗号分开,每一个采用以下形式:
+泛型形参列表中泛型形参用逗号分开,其中每一个采用以下形式:
-> `type parameter` : `constrain`
+> `类型形参` : `约束`
-泛型形参由两部分组成:类型形参及其后的可选约束。类型形参只是占位符类型(如T,U,V,KeyType,ValueType等)的名字而已。你可以在泛型类型、函数的其余部分或者构造器声明,以及函数或构造器的签名中使用它。
+泛型形参由两部分组成:类型形参及其后的可选约束。类型形参只是占位符类型(如 T,U,V,Key,Value 等)的名字而已。你可以在泛型类型、函数的其余部分或者初始化器声明,包括函数或初始化器的签名中使用它(与其任何相关类型)。
+
+约束用于指明该类型形参继承自某个类或者遵守某个协议或协议的一部分。例如,在下面的泛型函数中,泛型形参`T: Comparable`表示任何用于替代类型形参`T`的类型实参必须满足`Comparable`协议。
-约束用于指明该类型形参继承自某个类或者遵守某个协议或协议的一部分。例如,在下面的泛型中,泛型形参`T: Comparable`表示任何用于替代类型形参`T`的类型实参必须满足`Comparable`协议。
```swift
-func simpleMin