resolve conflict
This commit is contained in:
93
source/chapter2/01_The_Basics.md
Normal file → Executable file
93
source/chapter2/01_The_Basics.md
Normal file → Executable file
@ -11,7 +11,7 @@
|
||||
- [分号](#semicolons)
|
||||
- [整数](#integers)
|
||||
- [浮点数](#floating-point_numbers)
|
||||
- [类型安全和类型推测](#type_safety_and_type_inference)
|
||||
- [类型安全和类型推断](#type_safety_and_type_inference)
|
||||
- [数值型字面量](#numeric_literals)
|
||||
- [数值型类型转换](#numeric_type_conversion)
|
||||
- [类型别名](#type_aliases)
|
||||
@ -217,8 +217,9 @@ Swift 也提供了一个特殊的无符号类型`UInt`,长度与当前平台
|
||||
* 在32位平台上,`UInt`和`UInt32`长度相同。
|
||||
* 在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>
|
||||
## 浮点数
|
||||
@ -234,42 +235,42 @@ Swift 也提供了一个特殊的无符号类型`UInt`,长度与当前平台
|
||||
`Double`精确度很高,至少有15位数字,而`Float`最少只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围。
|
||||
|
||||
<a name="type_safety_and_type_inference"></a>
|
||||
## 类型安全和类型推测
|
||||
## 类型安全和类型推断
|
||||
|
||||
Swift 是一个_类型安全(type safe)_的语言。类型安全的语言可以让你清楚地知道代码要处理的值的类型。如果你的代码需要一个`String`,你绝对不可能不小心传进去一个`Int`。
|
||||
|
||||
由于 Swift 是类型安全的,所以它会在编译你的代码时进行_类型检查(type checks)_,并把不匹配的类型标记为错误。这可以让你在开发的时候尽早发现并修复错误。
|
||||
|
||||
当你要处理不同类型的值时,类型检查可以帮你避免错误。然而,这并不是说你每次声明常量和变量的时候都需要显式指定类型。如果你没有显式指定类型,Swift 会使用_类型推测(type inference)_来选择合适的类型。有了类型推测,编译器可以在编译代码的时候自动推测出表达式的类型。原理很简单,只要检查你赋的值即可。
|
||||
当你要处理不同类型的值时,类型检查可以帮你避免错误。然而,这并不是说你每次声明常量和变量的时候都需要显式指定类型。如果你没有显式指定类型,Swift 会使用_类型推断(type inference)_来选择合适的类型。有了类型推断,编译器可以在编译代码的时候自动推断出表达式的类型。原理很简单,只要检查你赋的值即可。
|
||||
|
||||
因为有类型推测,和 C 或者 Objective-C 比起来 Swift 很少需要声明类型。常量和变量虽然需要明确类型,但是大部分工作并不需要你自己来完成。
|
||||
因为有类型推断,和 C 或者 Objective-C 比起来 Swift 很少需要声明类型。常量和变量虽然需要明确类型,但是大部分工作并不需要你自己来完成。
|
||||
|
||||
当你声明常量或者变量并赋初值的时候类型推测非常有用。当你在声明常量或者变量的时候赋给它们一个_字面量(literal value 或 literal)_即可触发类型推测。(字面量就是会直接出现在你代码中的值,比如`42`和`3.14159`。)
|
||||
当你声明常量或者变量并赋初值的时候类型推断非常有用。当你在声明常量或者变量的时候赋给它们一个_字面量(literal value 或 literal)_即可触发类型推断。(字面量就是会直接出现在你代码中的值,比如`42`和`3.14159`。)
|
||||
|
||||
例如,如果你给一个新常量赋值`42`并且没有标明类型,Swift 可以推测出常量类型是`Int`,因为你给它赋的初始值看起来像一个整数:
|
||||
例如,如果你给一个新常量赋值`42`并且没有标明类型,Swift 可以推断出常量类型是`Int`,因为你给它赋的初始值看起来像一个整数:
|
||||
|
||||
```swift
|
||||
let meaningOfLife = 42
|
||||
// meaningOfLife 会被推测为 Int 类型
|
||||
```
|
||||
|
||||
同理,如果你没有给浮点字面量标明类型,Swift 会推测你想要的是`Double`:
|
||||
同理,如果你没有给浮点字面量标明类型,Swift 会推断你想要的是`Double`:
|
||||
|
||||
```swift
|
||||
let pi = 3.14159
|
||||
// pi 会被推测为 Double 类型
|
||||
```
|
||||
|
||||
当推测浮点数的类型时,Swift 总是会选择`Double`而不是`Float`。
|
||||
当推断浮点数的类型时,Swift 总是会选择`Double`而不是`Float`。
|
||||
|
||||
如果表达式中同时出现了整数和浮点数,会被推测为`Double`类型:
|
||||
如果表达式中同时出现了整数和浮点数,会被推断为`Double`类型:
|
||||
|
||||
```swift
|
||||
let anotherPi = 3 + 0.14159
|
||||
// anotherPi 会被推测为 Double 类型
|
||||
```
|
||||
|
||||
原始值`3`没有显式声明类型,而表达式中出现了一个浮点字面量,所以表达式会被推测为`Double`类型。
|
||||
原始值`3`没有显式声明类型,而表达式中出现了一个浮点字面量,所以表达式会被推断为`Double`类型。
|
||||
|
||||
<a name="numeric_literals"></a>
|
||||
## 数值型字面量
|
||||
@ -319,7 +320,7 @@ let justOverOneMillion = 1_000_000.000_000_1
|
||||
<a name="numeric_type_conversion"></a>
|
||||
## 数值型类型转换
|
||||
|
||||
通常来讲,即使代码中的整数常量和变量已知非负,也请使用`Int`类型。总是使用默认的整数类型可以保证你的整数常量和变量可以直接被复用并且可以匹配整数类字面量的类型推测。
|
||||
通常来讲,即使代码中的整数常量和变量已知非负,也请使用`Int`类型。总是使用默认的整数类型可以保证你的整数常量和变量可以直接被复用并且可以匹配整数类字面量的类型推断。
|
||||
只有在必要的时候才使用其他整数类型,比如要处理外部的长度明确的数据或者为了优化性能、内存占用等等。使用显式指定长度的类型可以及时发现值溢出并且可以暗示正在处理特殊数据。
|
||||
|
||||
### 整数转换
|
||||
@ -343,7 +344,7 @@ let one: UInt8 = 1
|
||||
let twoThousandAndOne = twoThousand + UInt16(one)
|
||||
```
|
||||
|
||||
现在两个数字的类型都是`UInt16`,可以进行相加。目标常量`twoThousandAndOne`的类型被推测为`UInt16`,因为它是两个`UInt16`值的和。
|
||||
现在两个数字的类型都是`UInt16`,可以进行相加。目标常量`twoThousandAndOne`的类型被推断为`UInt16`,因为它是两个`UInt16`值的和。
|
||||
|
||||
`SomeType(ofInitialValue)`是调用 Swift 构造器并传入一个初始值的默认方法。在语言内部,`UInt16`有一个构造器,可以接受一个`UInt8`类型的值,所以这个构造器可以用现有的`UInt8`来创建一个新的`UInt16`。注意,你并不能传入任意类型的值,只能传入`UInt16`内部有对应构造器的值。不过你可以扩展现有的类型来让它可以接收其他类型的值(包括自定义类型),请参考[扩展](20_Extensions.html)。
|
||||
|
||||
@ -358,7 +359,7 @@ let pi = Double(three) + pointOneFourOneFiveNine
|
||||
// pi 等于 3.14159,所以被推测为 Double 类型
|
||||
```
|
||||
|
||||
这个例子中,常量`three`的值被用来创建一个`Double`类型的值,所以加号两边的数类型相同。如果不进行转换,两者无法相加。
|
||||
这个例子中,常量`three`的值被用来创建一个`Double`类型的值,所以加号两边的数类型须相同。如果不进行转换,两者无法相加。
|
||||
|
||||
浮点数到整数的反向转换同样行,整数类型可以用`Double`或者`Float`类型来初始化:
|
||||
|
||||
@ -402,7 +403,7 @@ 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`语句的时候,布尔值非常有用:
|
||||
|
||||
@ -503,9 +504,9 @@ println("The status message is \(http200Status.description)")
|
||||
元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组。请参考[类和结构体](09_Classes_and_Structures.html)。
|
||||
|
||||
<a name="optionals"></a>
|
||||
## 可选
|
||||
## 可选类型
|
||||
|
||||
使用_可选(optionals)_来处理值可能缺失的情况。可选表示:
|
||||
使用_可选类型(optionals)_来处理值可能缺失的情况。可选类型表示:
|
||||
|
||||
* _有_值,等于 x
|
||||
|
||||
@ -513,8 +514,9 @@ println("The status message is \(http200Status.description)")
|
||||
|
||||
* _没有_值
|
||||
|
||||
> 注意:
|
||||
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"`不行。
|
||||
|
||||
@ -526,13 +528,13 @@ 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`或者什么都没有。)
|
||||
|
||||
### if 语句以及强制解析
|
||||
|
||||
你可以使用`if`语句来判断一个可选是否包含值。如果可选有值,结果是`true`;如果没有值,结果是`false`。
|
||||
你可以使用`if`语句来判断一个可选是否包含值。如果可选类型有值,结果是`true`;如果没有值,结果是`false`。
|
||||
|
||||
当你确定可选_确实_包含值之后,你可以在可选的名字后面加一个感叹号(`!`)来获取值。这个惊叹号表示“我知道这个可选有值,请使用它。”这被称为可选值的_强制解析(forced unwrapping)_:
|
||||
当你确定可选类型_确实_包含值之后,你可以在可选的名字后面加一个感叹号(`!`)来获取值。这个惊叹号表示“我知道这个可选有值,请使用它。”这被称为可选值的_强制解析(forced unwrapping)_:
|
||||
|
||||
```swift
|
||||
if convertedNumber {
|
||||
@ -551,7 +553,7 @@ if convertedNumber {
|
||||
<a name="optional_binding"></a>
|
||||
### 可选绑定
|
||||
|
||||
使用_可选绑定(optional binding)_来判断可选是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在`if`和`while`语句中来对可选的值进行判断并把值赋给一个常量或者变量。`if`和`while`语句,请参考[控制流](05_Control_Flow.html)。
|
||||
使用_可选绑定(optional binding)_来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在`if`和`while`语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。`if`和`while`语句,请参考[控制流](05_Control_Flow.html)。
|
||||
|
||||
像下面这样在`if`语句中写一个可选绑定:
|
||||
|
||||
@ -576,9 +578,9 @@ if let actualNumber = possibleNumber.toInt() {
|
||||
|
||||
“如果`possibleNumber.toInt`返回的可选`Int`包含一个值,创建一个叫做`actualNumber`的新常量并将可选包含的值赋给它。”
|
||||
|
||||
如果转换成功,`actualNumber`常量可以在`if`语句的第一个分支中使用。它已经被可选_包含的_值初始化过,所以不需要再使用`!`后缀来获取它的值。在这个例子中,`actualNumber`只被用来输出转换结果。
|
||||
如果转换成功,`actualNumber`常量可以在`if`语句的第一个分支中使用。它已经被可选类型_包含的_值初始化过,所以不需要再使用`!`后缀来获取它的值。在这个例子中,`actualNumber`只被用来输出转换结果。
|
||||
|
||||
你可以在可选绑定中使用常量和变量。如果你想在`if`语句的第一个分支中操作`actualNumber`的值,你可以改成`if var actualNumber`,这样可选包含的值就会被赋给一个变量而非常量。
|
||||
你可以在可选绑定中使用常量和变量。如果你想在`if`语句的第一个分支中操作`actualNumber`的值,你可以改成`if var actualNumber`,这样可选类型包含的值就会被赋给一个变量而非常量。
|
||||
|
||||
### nil
|
||||
|
||||
@ -601,20 +603,21 @@ 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`,不只是对象类型。
|
||||
|
||||
### 隐式解析可选
|
||||
### 隐式解析可选类型
|
||||
|
||||
如上所述,可选暗示了常量或者变量可以“没有值”。可选可以通过`if`语句来判断是否有值,如果有值的话可以通过可选绑定来解析值。
|
||||
如上所述,可选类型暗示了常量或者变量可以“没有值”。可选可以通过`if`语句来判断是否有值,如果有值的话可以通过可选绑定来解析值。
|
||||
|
||||
有时候在程序架构中,第一次被赋值之后,可以确定一个可选_总会_有值。在这种情况下,每次都要判断和解析可选值是非常低效的,因为可以确定它总会有值。
|
||||
有时候在程序架构中,第一次被赋值之后,可以确定一个可选类型_总会_有值。在这种情况下,每次都要判断和解析可选值是非常低效的,因为可以确定它总会有值。
|
||||
|
||||
这种类型的可选被定义为_隐式解析可选(implicitly unwrapped optionals)_。把想要用作可选的类型的后面的问号(`String?`)改成感叹号(`String!`)来声明一个隐式解析可选。
|
||||
这种类型的可选状态被定义为_隐式解析可选类型(implicitly unwrapped optionals)_。把想要用作可选的类型的后面的问号(`String?`)改成感叹号(`String!`)来声明一个隐式解析可选类型。
|
||||
|
||||
当可选被第一次赋值之后就可以确定之后一直有值的时候,隐式解析可选非常有用。隐式解析可选主要被用在 Swift 中类的构造过程中,请参考[类实例之间的循环强引用](16_Automatic_Reference_Counting.html#strong_reference_cycles_between_class_instances)。
|
||||
当可选类型被第一次赋值之后就可以确定之后一直有值的时候,隐式解析可选类型非常有用。隐式解析可选类型主要被用在 Swift 中类的构造过程中,请参考[类实例之间的循环强引用](16_Automatic_Reference_Counting.html#strong_reference_cycles_between_class_instances)。
|
||||
|
||||
一个隐式解析可选其实就是一个普通的可选,但是可以被当做非可选来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选`String`和隐式解析可选`String`之间的区别:
|
||||
一个隐式解析可选类型其实就是一个普通的可选类型,但是可以被当做非可选类型来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选类型`String`和隐式解析可选类型`String`之间的区别:
|
||||
|
||||
```swift
|
||||
let possibleString: String? = "An optional string."
|
||||
@ -628,12 +631,13 @@ println(assumedString) // 不需要感叹号
|
||||
// 输出 "An implicitly unwrapped optional string."
|
||||
```
|
||||
|
||||
你可以把隐式解析可选当做一个可以自动解析的可选。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。
|
||||
你可以把隐式解析可选类型当做一个可以自动解析的可选类型。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。
|
||||
|
||||
> 注意:
|
||||
如果你在隐式解析可选没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选后面加一个惊叹号一样。
|
||||
> 注意:
|
||||
>
|
||||
如果你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一个惊叹号一样。
|
||||
|
||||
你仍然可以把隐式解析可选当做普通可选来判断它是否包含值:
|
||||
你仍然可以把隐式解析可选类型当做普通可选类型来判断它是否包含值:
|
||||
|
||||
```swift
|
||||
if assumedString {
|
||||
@ -642,7 +646,7 @@ if assumedString {
|
||||
// 输出 "An implicitly unwrapped optional string."
|
||||
```
|
||||
|
||||
你也可以在可选绑定中使用隐式解析可选来检查并解析它的值:
|
||||
你也可以在可选绑定中使用隐式解析可选类型来检查并解析它的值:
|
||||
|
||||
```swift
|
||||
if let definiteString = assumedString {
|
||||
@ -651,13 +655,14 @@ if let definiteString = assumedString {
|
||||
// 输出 "An implicitly unwrapped optional string."
|
||||
```
|
||||
|
||||
> 注意:
|
||||
如果一个变量之后可能变成`nil`的话请不要使用隐式解析可选。如果你需要在变量的生命周期中判断是否是`nil`的话,请使用普通可选类型。
|
||||
> 注意:
|
||||
>
|
||||
如果一个变量之后可能变成`nil`的话请不要使用隐式解析可选类型。如果你需要在变量的生命周期中判断是否是`nil`的话,请使用普通可选类型。
|
||||
|
||||
<a name="assertions"></a>
|
||||
## 断言
|
||||
|
||||
可选可以让你判断值是否存在,你可以在代码中优雅地处理值缺失的情况。然而,在某些情况下,如果值缺失或者值并不满足特定的条件,你的代码可能并不需要继续执行。这时,你可以在你的代码中触发一个_断言(assertion)_来结束代码运行并通过调试来找到值缺失的原因。
|
||||
可选类型可以让你判断值是否存在,你可以在代码中优雅地处理值缺失的情况。然而,在某些情况下,如果值缺失或者值并不满足特定的条件,你的代码可能并不需要继续执行。这时,你可以在你的代码中触发一个_断言(assertion)_来结束代码运行并通过调试来找到值缺失的原因。
|
||||
|
||||
### 使用断言进行调试
|
||||
|
||||
@ -685,11 +690,11 @@ assert(age >= 0)
|
||||
|
||||
当条件可能为假时使用断言,但是最终一定要_保证_条件为真,这样你的代码才能继续运行。断言的适用情景:
|
||||
|
||||
* 整数的附属脚本索引被传入一个自定义附属脚本实现,但是下标索引值可能太小或者太大。
|
||||
* 整数类型的下标索引被传入一个自定义下标脚本实现,但是下标索引值可能太小或者太大。
|
||||
* 需要给函数传入一个值,但是非法的值可能导致函数不能正常执行。
|
||||
* 一个可选值现在是`nil`,但是后面的代码运行需要一个非`nil`值。
|
||||
|
||||
请参考[附属脚本](12_Subscripts.html)和[函数](06_Functions.html)。
|
||||
请参考[下标脚本](12_Subscripts.html)和[函数](06_Functions.html)。
|
||||
|
||||
> 注意:
|
||||
断言可能导致你的应用终止运行,所以你应当仔细设计你的代码来让非法条件不会出现。然而,在你的应用发布之前,有时候非法条件可能出现,这时使用断言可以快速发现问题。
|
||||
|
||||
0
source/chapter2/02_Basic_Operators.md
Normal file → Executable file
0
source/chapter2/02_Basic_Operators.md
Normal file → Executable file
4
source/chapter2/03_Strings_and_Characters.md
Normal file → Executable file
4
source/chapter2/03_Strings_and_Characters.md
Normal file → Executable file
@ -354,7 +354,7 @@ print("\n")
|
||||
// 68 111 103 33 240 159 144 182
|
||||
```
|
||||
|
||||
上面的例子中,前四个10进制代码单元值 (68, 111, 103, 33) 代表了字符`D` `o` `g`和`!`,他们的 UTF-8 表示与 ASCII 表示相同。
|
||||
上面的例子中,前四个10进制代码单元值 (68, 111, 103, 33) 代表了字符`D` `o` `g`和`!`,它们的 UTF-8 表示与 ASCII 表示相同。
|
||||
后四个代码单元值 (240, 159, 144, 182) 是`DOG FACE`的4字节 UTF-8 表示。
|
||||
|
||||
<a name="UTF-16"></a>
|
||||
@ -371,7 +371,7 @@ print("\n")
|
||||
// 68 111 103 33 55357 56374
|
||||
```
|
||||
|
||||
同样,前四个代码单元值 (68, 111, 103, 33) 代表了字符`D` `o` `g`和`!`,他们的 UTF-16 代码单元和 UTF-8 完全相同。
|
||||
同样,前四个代码单元值 (68, 111, 103, 33) 代表了字符`D` `o` `g`和`!`,它们的 UTF-16 代码单元和 UTF-8 完全相同。
|
||||
|
||||
第五和第六个代码单元值 (55357 和 56374) 是`DOG FACE`字符的UTF-16 表示。
|
||||
第一个值为`U+D83D`(十进制值为 55357),第二个值为`U+DC36`(十进制值为 56374)。
|
||||
|
||||
42
source/chapter2/04_Collection_Types.md
Normal file → Executable file
42
source/chapter2/04_Collection_Types.md
Normal file → Executable file
@ -22,7 +22,7 @@ Swift 的数组结构在被声明成常量和变量或者被传入函数与方
|
||||
|
||||
数组使用有序列表存储相同类型的多重数据。相同的值可以多次出现在一个数组的不同位置中。
|
||||
|
||||
Swift 数组对存储数据有具体要求。 不同于 Objective-C 的`NSArray`和`NSMutableArray`类,他们可以存储任何类型的实例而且不提供他们返回对象的任何本质信息。 在 Swift 中,数据值在被存储进入某个数组之前类型必须明确,方法是通过显式的类型标注或类型推断,而且不是必须是`class`类型。例如: 如果我们创建了一个`Int`值类型的数组,我们不能往其中插入任何不是`Int`类型的数据。 Swift 中的数组是类型安全的,并且它们中包含的类型必须明确。
|
||||
Swift 数组对存储数据有具体要求。 不同于 Objective-C 的`NSArray`和`NSMutableArray`类,它们可以存储任何类型的实例而且不提供它们返回对象的任何本质信息。 在 Swift 中,数据值在被存储进入某个数组之前类型必须明确,方法是通过显式的类型标注或类型推断,而且不是必须是`class`类型。例如: 如果我们创建了一个`Int`值类型的数组,我们不能往其中插入任何不是`Int`类型的数据。 Swift 中的数组是类型安全的,并且它们中包含的类型必须明确。
|
||||
|
||||
<a name="array_type_shorthand_syntax"></a>
|
||||
### 数组的简单语法
|
||||
@ -32,7 +32,7 @@ Swift 数组对存储数据有具体要求。 不同于 Objective-C 的`NSArray`
|
||||
<a name="array_literals"></a>
|
||||
### 数组构造语句
|
||||
|
||||
我们可以使用字面语句来进行数组构造,这是一种用一个或者多个数值构造数组的简单方法。字面语句是一系列由逗号分割并由方括号包含的数值。
|
||||
我们可以使用字面量来进行数组构造,这是一种用一个或者多个数值构造数组的简单方法。字面量是一系列由逗号分割并由方括号包含的数值。
|
||||
`[value 1, value 2, value 3]`。
|
||||
|
||||
下面这个例子创建了一个叫做`shoppingList`并且存储字符串的数组:
|
||||
@ -42,20 +42,20 @@ 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`创建)是因为以后可能会有更多的数据项被插入其中。
|
||||
|
||||
在这个例子中,字面语句仅仅包含两个`String`值。匹配了该数组的变量声明(只能包含`String`的数组),所以这个字面语句的分配过程就是允许用两个初始项来构造`shoppinglist`。
|
||||
在这个例子中,字面量仅仅包含两个`String`值。匹配了该数组的变量声明(只能包含`String`的数组),所以这个字面量的分配过程就是允许用两个初始项来构造`shoppinglist`。
|
||||
|
||||
由于 Swift 的类型推断机制,当我们用字面语句构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。 `shoppinglist`的构造也可以这样写:
|
||||
由于 Swift 的类型推断机制,当我们用字面量构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。 `shoppinglist`的构造也可以这样写:
|
||||
|
||||
```swift
|
||||
var shoppingList = ["Eggs", "Milk"]
|
||||
```
|
||||
|
||||
因为所有字面语句中的值都是相同的类型,Swift 可以推断出`String[]`是`shoppinglist`中变量的正确类型。
|
||||
因为所有字面量中的值都是相同的类型,Swift 可以推断出`String[]`是`shoppinglist`中变量的正确类型。
|
||||
|
||||
<a name="accessing_and_modifying_an_array"></a>
|
||||
### 访问和修改数组
|
||||
@ -123,8 +123,14 @@ shoppingList[4...6] = ["Bananas", "Apples"]
|
||||
// shoppingList 现在有六项
|
||||
```
|
||||
|
||||
<<<<<<< HEAD
|
||||
> 注意:
|
||||
>我们不能使用下标语法在数组尾部添加新项。如果我们试着用这种方法对索引越界的数据进行检索或者设置新值的操作,我们会引发一个运行期错误。我们可以使用索引值和数组的`count`属性进行比较来在使用某个索引之前先检验是否有效。除了当`count`等于 0 时(说明这是个空数组),最大索引值一直是`count - 1`,因为数组都是零起索引。
|
||||
=======
|
||||
> 注意:
|
||||
>
|
||||
>我们不能使用下标语法在数组尾部添加新项。如果我们试着用这种方法对索引越界的数据进行检索或者设置新值的操作,我们会引发一个运行时错误。我们可以使用索引值和数组的`count`属性进行比较来在使用某个索引之前先检验是否有效。除了当`count`等于 0 时(说明这是个空数组),最大索引值一直是`count - 1`,因为数组都是零起索引。
|
||||
>>>>>>> a516af6a531a104ec88da0d236ecf389a5ec72af
|
||||
|
||||
调用数组的`insert(atIndex:)`方法来在某个具体索引值之前添加数据项:
|
||||
|
||||
@ -177,7 +183,7 @@ for item in shoppingList {
|
||||
// Bananas
|
||||
```
|
||||
|
||||
如果我们同时需要每个数据项的值和索引值,可以使用全局`enumerate`函数来进行数组遍历。`enumerate`返回一个由每一个数据项索引值和数据值组成的键值对组。我们可以把这个键值对组分解成临时常量或者变量来进行遍历:
|
||||
如果我们同时需要每个数据项的值和索引值,可以使用全局`enumerate`函数来进行数组遍历。`enumerate`返回一个由每一个数据项索引值和数据值组成的元组。我们可以把这个元组分解成临时常量或者变量来进行遍历:
|
||||
|
||||
```swift
|
||||
for (index, value) in enumerate(shoppingList) {
|
||||
@ -238,7 +244,7 @@ var sixDoubles = threeDoubles + anotherThreeDoubles
|
||||
<a name="dictionaries"></a>
|
||||
## 字典
|
||||
|
||||
字典是一种存储相同类型多重数据的存储器。每个值(value)都关联独特的键(key),键作为字典中的这个值数据的标识符。和数组中的数据项不同,字典中的数据项并没有具体顺序。我们在需要通过标识符(键)访问数据的时候使用字典,这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。
|
||||
字典是一种存储多个相同类型的值的容器。每个值(value)都关联唯一的键(key),键作为字典中的这个值数据的标识符。和数组中的数据项不同,字典中的数据项并没有具体顺序。我们在需要通过标识符(键)访问数据的时候使用字典,这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。
|
||||
|
||||
Swift 的字典使用时需要具体规定可以存储键和值类型。不同于 Objective-C 的`NSDictionary`和`NSMutableDictionary` 类可以使用任何类型的对象来作键和值并且不提供任何关于这些对象的本质信息。在 Swift 中,在某个特定字典中可以存储的键和值必须提前定义清楚,方法是通过显性类型标注或者类型推断。
|
||||
|
||||
@ -247,11 +253,11 @@ Swift 的字典使用`Dictionary<KeyType, ValueType>`定义,其中`KeyType`是
|
||||
`KeyType`的唯一限制就是可哈希的,这样可以保证它是独一无二的,所有的 Swift 基本类型(例如`String`,`Int`, `Double`和`Bool`)都是默认可哈希的,并且所有这些类型都可以在字典中当做键使用。未关联值的枚举成员(参见[枚举](08_Enumerations.html))也是默认可哈希的。
|
||||
|
||||
<a name="dictionary_literals"></a>
|
||||
## 字典字面语句
|
||||
## 字典字面量
|
||||
|
||||
我们可以使用字典字面语句来构造字典,他们和我们刚才介绍过的数组字面语句拥有相似语法。一个字典字面语句是一个定义拥有一个或者多个键值对的字典集合的简单语句。
|
||||
我们可以使用字典字面量来构造字典,它们和我们刚才介绍过的数组字面量拥有相似语法。一个字典字面量是一个定义拥有一个或者多个键值对的字典集合的简单语句。
|
||||
|
||||
一个键值对是一个`key`和一个`value`的结合体。在字典字面语句中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含并且由逗号分割:
|
||||
一个键值对是一个`key`和一个`value`的结合体。在字典字面量中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含并且由逗号分割:
|
||||
|
||||
```swift
|
||||
[key 1: value 1, key 2: value 2, key 3: value 3]
|
||||
@ -268,11 +274,11 @@ var airports: Dictionary<String, String> = ["TYO": "Tokyo", "DUB": "Dublin"]
|
||||
> 注意:
|
||||
> `airports`字典被声明为变量(用`var`关键字)而不是常量(`let`关键字)因为后来更多的机场信息会被添加到这个示例字典中。
|
||||
|
||||
`airports`字典使用字典字面语句初始化,包含两个键值对。第一对的键是`TYO`,值是`Tokyo`。第二对的键是`DUB`,值是`Dublin`。
|
||||
`airports`字典使用字典字面量初始化,包含两个键值对。第一对的键是`TYO`,值是`Tokyo`。第二对的键是`DUB`,值是`Dublin`。
|
||||
|
||||
这个字典语句包含了两个`String: String`类型的键值对。他们对应`airports`变量声明的类型(一个只有`String`键和`String`值的字典)所以这个字典字面语句是构造两个初始数据项的`airport`字典。
|
||||
这个字典语句包含了两个`String: String`类型的键值对。它们对应`airports`变量声明的类型(一个只有`String`键和`String`值的字典)所以这个字典字面量是构造两个初始数据项的`airport`字典。
|
||||
|
||||
和数组一样,如果我们使用字面语句构造字典就不用把类型定义清楚。`airports`的也可以用这种方法简短定义:
|
||||
和数组一样,如果我们使用字面量构造字典就不用把类型定义清楚。`airports`的也可以用这种方法简短定义:
|
||||
|
||||
```swift
|
||||
var airports = ["TYO": "Tokyo", "DUB": "Dublin"]
|
||||
@ -349,7 +355,7 @@ if let removedValue = airports.removeValueForKey("DUB") {
|
||||
<a name="iterating_over_a_dictionary"></a>
|
||||
### 字典遍历
|
||||
|
||||
我们可以使用`for-in`循环来遍历某个字典中的键值对。每一个字典中的数据项都由`(key, value)`元组形式返回,并且我们可以使用暂时性常量或者变量来分解这些元组:
|
||||
我们可以使用`for-in`循环来遍历某个字典中的键值对。每一个字典中的数据项都由`(key, value)`元组形式返回,并且我们可以使用临时常量或者变量来分解这些元组:
|
||||
|
||||
```swift
|
||||
for (airportCode, airportName) in airports {
|
||||
@ -360,7 +366,7 @@ for (airportCode, airportName) in airports {
|
||||
```
|
||||
`for-in`循环请参见[For 循环](05_Control_Flow.html#for_loops)。
|
||||
|
||||
我们也可以通过访问他的`keys`或者`values`属性(都是可遍历集合)检索一个字典的键或者值:
|
||||
我们也可以通过访问它的`keys`或者`values`属性(都是可遍历集合)检索一个字典的键或者值:
|
||||
|
||||
```swift
|
||||
for airportCode in airports.keys {
|
||||
@ -405,7 +411,7 @@ var namesOfIntegers = Dictionary<Int, String>()
|
||||
|
||||
这个例子创建了一个`Int, String`类型的空字典来储存英语对整数的命名。它的键是`Int`型,值是`String`型。
|
||||
|
||||
如果上下文已经提供了信息类型,我们可以使用空字典字面语句来创建一个空字典,记作`[:]`(中括号中放一个冒号):
|
||||
如果上下文已经提供了信息类型,我们可以使用空字典字面量来创建一个空字典,记作`[:]`(中括号中放一个冒号):
|
||||
|
||||
```swift
|
||||
namesOfIntegers[16] = "sixteen"
|
||||
@ -420,7 +426,7 @@ namesOfIntegers = [:]
|
||||
<a name="mutability_of_collections"></a>
|
||||
## 集合的可变性
|
||||
|
||||
数组和字典都是在单个集合中存储可变值。如果我们创建一个数组或者字典并且把它分配成一个变量,这个集合将会是可变的。这意味着我们可以在创建之后添加更多或移除已存在的数据项来改变这个集合的大小。与此相反,如果我们把数组或字典分配成常量,那么他就是不可变的,它的大小不能被改变。
|
||||
数组和字典都是在单个集合中存储可变值。如果我们创建一个数组或者字典并且把它分配成一个变量,这个集合将会是可变的。这意味着我们可以在创建之后添加更多或移除已存在的数据项来改变这个集合的大小。与此相反,如果我们把数组或字典分配成常量,那么它就是不可变的,它的大小不能被改变。
|
||||
|
||||
对字典来说,不可变性也意味着我们不能替换其中任何现有键所对应的值。不可变字典的内容在被首次设定之后不能更改。
|
||||
不可变性对数组来说有一点不同,当然我们不能试着改变任何不可变数组的大小,但是我们可以重新设定相对现存索引所对应的值。这使得 Swift 数组在大小被固定的时候依然可以做的很棒。
|
||||
|
||||
2
source/chapter2/05_Control_Flow.md
Normal file → Executable file
2
source/chapter2/05_Control_Flow.md
Normal file → Executable file
@ -13,7 +13,7 @@
|
||||
|
||||
Swift提供了类似 C 语言的流程控制结构,包括可以多次执行任务的`for`和`while`循环,基于特定条件选择执行不同代码分支的`if`和`switch`语句,还有控制流程跳转到其他代码的`break`和`continue`语句。
|
||||
|
||||
除了 C 语言里面传统的for条件递增(`for-condition-increment`)循环,Swift 还增加了`for-in`循环,用来更简单地遍历数组(array),字典(dictionary),区间(range),字符串(string)和其他序列类型。
|
||||
除了 C 语言里面传统的 for 条件递增(`for-condition-increment`)循环,Swift 还增加了`for-in`循环,用来更简单地遍历数组(array),字典(dictionary),区间(range),字符串(string)和其他序列类型。
|
||||
|
||||
Swift 的`switch`语句比 C 语言中更加强大。在 C 语言中,如果某个 case 不小心漏写了`break`,这个 case 就会贯穿(fallthrough)至下一个 case,Swift 无需写`break`,所以不会发生这种贯穿(fallthrough)的情况。case 还可以匹配更多的类型模式,包括区间匹配(range matching),元组(tuple)和特定类型的描述。`switch`的 case 语句中匹配的值可以是由 case 体内部临时的常量或者变量决定,也可以由`where`分句描述更复杂的匹配条件。
|
||||
|
||||
|
||||
4
source/chapter2/06_Functions.md
Normal file → Executable file
4
source/chapter2/06_Functions.md
Normal file → Executable file
@ -466,7 +466,7 @@ println("Result: \(mathFunction(2, 3))")
|
||||
// prints "Result: 6"
|
||||
```
|
||||
|
||||
就像其他类型一样,当赋值一个函数给常量或变量时,你可以让 Swift 来推测其函数类型:
|
||||
就像其他类型一样,当赋值一个函数给常量或变量时,你可以让 Swift 来推断其函数类型:
|
||||
|
||||
```swift
|
||||
let anotherMathFunction = addTwoInts
|
||||
@ -570,4 +570,4 @@ println("zero!")
|
||||
// -2...
|
||||
// -1...
|
||||
// zero!
|
||||
```
|
||||
```
|
||||
|
||||
2
source/chapter2/07_Closures.md
Normal file → Executable file
2
source/chapter2/07_Closures.md
Normal file → Executable file
@ -221,7 +221,7 @@ let digitNames = [
|
||||
let numbers = [16, 58, 510]
|
||||
```
|
||||
|
||||
如上代码创建了一个数字位和他们名字映射的英文版本字典。
|
||||
如上代码创建了一个数字位和它们名字映射的英文版本字典。
|
||||
同时定义了一个准备转换为字符串的整型数组。
|
||||
|
||||
您现在可以通过传递一个尾随闭包给`numbers`的`map`方法来创建对应的字符串版本数组。
|
||||
|
||||
0
source/chapter2/08_Enumerations.md
Normal file → Executable file
0
source/chapter2/08_Enumerations.md
Normal file → Executable file
11
source/chapter2/09_Classes_and_Structures.md
Normal file → Executable file
11
source/chapter2/09_Classes_and_Structures.md
Normal file → Executable file
@ -22,14 +22,23 @@
|
||||
###类和结构体对比
|
||||
Swift 中类和结构体有很多共同点。共同处在于:
|
||||
|
||||
<<<<<<< HEAD
|
||||
* 定义属性用于储存值
|
||||
* 定义方法用于提供功能
|
||||
* 定义附属脚本用于访问值
|
||||
* 定义构造器用于生成初始化值
|
||||
* 通过扩展以增加默认实现的功能
|
||||
* 符合协议以对某类提供标准功能
|
||||
=======
|
||||
* 定义属性用于储存值
|
||||
* 定义方法用于提供功能
|
||||
* 定义下标脚本用于访问值
|
||||
* 定义构造器用于生成初始化值
|
||||
* 通过扩展以增加默认实现的功能
|
||||
* 符合协议以对某类提供标准功能
|
||||
>>>>>>> a516af6a531a104ec88da0d236ecf389a5ec72af
|
||||
|
||||
更多信息请参见 [属性](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)。
|
||||
|
||||
与结构体相比,类还有如下的附加功能:
|
||||
|
||||
|
||||
14
source/chapter2/10_Properties.md
Normal file → Executable file
14
source/chapter2/10_Properties.md
Normal file → Executable file
@ -25,7 +25,7 @@
|
||||
|
||||
可以在定义存储属性的时候指定默认值,请参考[构造过程](../chapter2/14_Initialization.html)一章的[默认属性值](../chapter2/14_Initialization.html#default_property_values)一节。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值,请参考[构造过程](../chapter2/14_Initialization.html)一章的[在初始化阶段修改常量存储属性](../chapter2/14_Initialization.html#modifying_constant_properties_during_initialization)一节。
|
||||
|
||||
下面的例子定义了一个名为`FixedLengthRange`的结构体,他描述了一个在创建后无法修改值域宽度的区间:
|
||||
下面的例子定义了一个名为`FixedLengthRange`的结构体,它描述了一个在创建后无法修改值域宽度的区间:
|
||||
|
||||
```swift
|
||||
struct FixedLengthRange {
|
||||
@ -193,8 +193,14 @@ struct AlternativeRect {
|
||||
|
||||
只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。
|
||||
|
||||
<<<<<<< HEAD
|
||||
> 注意:
|
||||
> 必须使用`var`关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。
|
||||
=======
|
||||
> 注意:
|
||||
>
|
||||
> 必须使用`var`关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。
|
||||
>>>>>>> a516af6a531a104ec88da0d236ecf389a5ec72af
|
||||
|
||||
只读计算属性的声明可以去掉`get`关键字和花括号:
|
||||
|
||||
@ -231,8 +237,14 @@ println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
|
||||
|
||||
类似地,`didSet`监视器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名`oldValue`。
|
||||
|
||||
<<<<<<< HEAD
|
||||
> 注意:
|
||||
> `willSet`和`didSet`监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用。
|
||||
=======
|
||||
> 注意:
|
||||
>
|
||||
> `willSet`和`didSet`监视器在属性初始化过程中不会被调用,它们只会当属性的值在初始化之外的地方被设置时被调用。
|
||||
>>>>>>> a516af6a531a104ec88da0d236ecf389a5ec72af
|
||||
|
||||
这里是一个`willSet`和`didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数,可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。
|
||||
|
||||
|
||||
6
source/chapter2/11_Methods.md
Normal file → Executable file
6
source/chapter2/11_Methods.md
Normal file → Executable file
@ -285,7 +285,7 @@ class Player {
|
||||
}
|
||||
```
|
||||
|
||||
`Player`类创建一个新的`LevelTracker`实例来监测这个用户的发展进度。他提供了`completedLevel`方法:一旦玩家完成某个指定等级就调用它。这个方法为所有玩家解锁下一等级,并且将当前玩家的进度更新为下一等级。(我们忽略了`advanceToLevel`返回的布尔值,因为之前调用`LevelTracker.unlockLevel`时就知道了这个等级已经被解锁了)。
|
||||
`Player`类创建一个新的`LevelTracker`实例来监测这个用户的发展进度。它提供了`completedLevel`方法:一旦玩家完成某个指定等级就调用它。这个方法为所有玩家解锁下一等级,并且将当前玩家的进度更新为下一等级。(我们忽略了`advanceToLevel`返回的布尔值,因为之前调用`LevelTracker.unlockLevel`时就知道了这个等级已经被解锁了)。
|
||||
|
||||
你还可以为一个新的玩家创建一个`Player`的实例,然后看这个玩家完成等级一时发生了什么:
|
||||
|
||||
@ -296,7 +296,7 @@ println("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
|
||||
// 输出 "highest unlocked level is now 2"(最高等级现在是2)
|
||||
```
|
||||
|
||||
如果你创建了第二个玩家,并尝试让他开始一个没有被任何玩家解锁的等级,那么这次设置玩家当前等级的尝试将会失败:
|
||||
如果你创建了第二个玩家,并尝试让它开始一个没有被任何玩家解锁的等级,那么这次设置玩家当前等级的尝试将会失败:
|
||||
|
||||
```swift
|
||||
player = Player(name: "Beto")
|
||||
@ -306,4 +306,4 @@ if player.tracker.advanceToLevel(6) {
|
||||
println("level 6 has not yet been unlocked")
|
||||
}
|
||||
// 输出 "level 6 has not yet been unlocked"(等级6还没被解锁)
|
||||
```
|
||||
```
|
||||
|
||||
62
source/chapter2/12_Subscripts.md
Normal file → Executable file
62
source/chapter2/12_Subscripts.md
Normal file → Executable file
@ -2,25 +2,29 @@
|
||||
> 校对:zq54zquan
|
||||
|
||||
|
||||
# 附属脚本(Subscripts)
|
||||
# 下标脚本(Subscripts)
|
||||
-----------------
|
||||
|
||||
本页包含内容:
|
||||
|
||||
- [附属脚本语法](#subscript_syntax)
|
||||
- [附属脚本用法](#subscript_usage)
|
||||
- [附属脚本选项](#subscript_options)
|
||||
- [下标脚本语法](#subscript_syntax)
|
||||
- [下标脚本用法](#subscript_usage)
|
||||
- [下标脚本选项](#subscript_options)
|
||||
|
||||
*附属脚本* 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问对象、集合或序列的快捷方式,不需要再调用实例的特定的赋值和访问方法。举例来说,用附属脚本访问一个数组(Array)实例中的元素可以这样写 `someArray[index]` ,访问字典(Dictionary)实例中的元素可以这样写 `someDictionary[key]`。
|
||||
*下标脚本* 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问对象、集合或序列的快捷方式,不需要再调用实例的特定的赋值和访问方法。举例来说,用下标脚本访问一个数组(Array)实例中的元素可以这样写 `someArray[index]` ,访问字典(Dictionary)实例中的元素可以这样写 `someDictionary[key]`。
|
||||
|
||||
对于同一个目标可以定义多个附属脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。
|
||||
对于同一个目标可以定义多个下标脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。
|
||||
|
||||
<<<<<<< HEAD
|
||||
> 译者:这里附属脚本重载在本小节中原文并没有任何演示
|
||||
=======
|
||||
> 译者:这里下标脚本重载在本小节中原文并没有任何演示
|
||||
>>>>>>> a516af6a531a104ec88da0d236ecf389a5ec72af
|
||||
|
||||
<a name="subscript_syntax"></a>
|
||||
## 附属脚本语法
|
||||
## 下标脚本语法
|
||||
|
||||
附属脚本允许你通过在实例后面的方括号中传入一个或者多个的索引值来对实例进行访问和赋值。语法类似于实例方法和计算型属性的混合。与定义实例方法类似,定义附属脚本使用`subscript`关键字,显式声明入参(一个或多个)和返回类型。与实例方法不同的是附属脚本可以设定为读写或只读。这种方式又有点像计算型属性的getter和setter:
|
||||
下标脚本允许你通过在实例后面的方括号中传入一个或者多个的索引值来对实例进行访问和赋值。语法类似于实例方法和计算型属性的混合。与定义实例方法类似,定义下标脚本使用`subscript`关键字,显式声明入参(一个或多个)和返回类型。与实例方法不同的是下标脚本可以设定为读写或只读。这种方式又有点像计算型属性的getter和setter:
|
||||
|
||||
```swift
|
||||
subscript(index: Int) -> Int {
|
||||
@ -34,7 +38,7 @@ subscript(index: Int) -> Int {
|
||||
}
|
||||
```
|
||||
|
||||
`newValue`的类型必须和附属脚本定义的返回类型相同。与计算型属性相同的是set的入参声明`newValue`就算不写,在set代码块中依然可以使用默认的`newValue`这个变量来访问新赋的值。
|
||||
`newValue`的类型必须和下标脚本定义的返回类型相同。与计算型属性相同的是set的入参声明`newValue`就算不写,在set代码块中依然可以使用默认的`newValue`这个变量来访问新赋的值。
|
||||
|
||||
与只读计算型属性一样,可以直接将原本应该写在`get`代码块中的代码写在`subscript`中:
|
||||
|
||||
@ -44,7 +48,7 @@ subscript(index: Int) -> Int {
|
||||
}
|
||||
```
|
||||
|
||||
下面代码演示了一个在`TimesTable`结构体中使用只读附属脚本的用法,该结构体用来展示传入整数的*n*倍。
|
||||
下面代码演示了一个在`TimesTable`结构体中使用只读下标脚本的用法,该结构体用来展示传入整数的*n*倍。
|
||||
|
||||
```swift
|
||||
struct TimesTable {
|
||||
@ -60,39 +64,51 @@ println("3的6倍是\(threeTimesTable[6])")
|
||||
|
||||
在上例中,通过`TimesTable`结构体创建了一个用来表示索引值三倍的实例。数值`3`作为结构体`构造函数`入参初始化实例成员`multiplier`。
|
||||
|
||||
你可以通过附属脚本来得到结果,比如`threeTimesTable[6]`。这条语句访问了`threeTimesTable`的第六个元素,返回`6`的`3`倍即`18`。
|
||||
你可以通过下标脚本来得到结果,比如`threeTimesTable[6]`。这条语句访问了`threeTimesTable`的第六个元素,返回`6`的`3`倍即`18`。
|
||||
|
||||
<<<<<<< HEAD
|
||||
>注意:
|
||||
> `TimesTable`例子是基于一个固定的数学公式。它并不适合开放写权限来对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么附属脚本只定义为只读的原因。
|
||||
=======
|
||||
>注意:
|
||||
>
|
||||
> `TimesTable`例子是基于一个固定的数学公式。它并不适合开放写权限来对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么下标脚本只定义为只读的原因。
|
||||
>>>>>>> a516af6a531a104ec88da0d236ecf389a5ec72af
|
||||
|
||||
|
||||
<a name="subscript_usage"></a>
|
||||
## 附属脚本用法
|
||||
## 下标脚本用法
|
||||
|
||||
根据使用场景不同附属脚本也具有不同的含义。通常附属脚本是用来访问集合(collection),列表(list)或序列(sequence)中元素的快捷方式。你可以在你自己特定的类或结构体中自由的实现附属脚本来提供合适的功能。
|
||||
根据使用场景不同下标脚本也具有不同的含义。通常下标脚本是用来访问集合(collection),列表(list)或序列(sequence)中元素的快捷方式。你可以在你自己特定的类或结构体中自由的实现下标脚本来提供合适的功能。
|
||||
|
||||
例如,Swift 的字典(Dictionary)实现了通过附属脚本来对其实例中存放的值进行存取操作。在附属脚本中使用和字典索引相同类型的值,并且把一个字典值类型的值赋值给这个附属脚本来为字典设值:
|
||||
例如,Swift 的字典(Dictionary)实现了通过下标脚本来对其实例中存放的值进行存取操作。在下标脚本中使用和字典索引相同类型的值,并且把一个字典值类型的值赋值给这个下标脚本来为字典设值:
|
||||
|
||||
```swift
|
||||
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
|
||||
numberOfLegs["bird"] = 2
|
||||
```
|
||||
|
||||
上例定义一个名为`numberOfLegs`的变量并用一个字典字面量初始化出了包含三对键值的字典实例。`numberOfLegs`的字典存放值类型推断为`Dictionary<String, Int>`。字典实例创建完成之后通过附属脚本的方式将整型值`2`赋值到字典实例的索引为`bird`的位置中。
|
||||
上例定义一个名为`numberOfLegs`的变量并用一个字典字面量初始化出了包含三对键值的字典实例。`numberOfLegs`的字典存放值类型推断为`Dictionary<String, Int>`。字典实例创建完成之后通过下标脚本的方式将整型值`2`赋值到字典实例的索引为`bird`的位置中。
|
||||
|
||||
更多关于字典(Dictionary)附属脚本的信息请参考[读取和修改字典](../chapter2/04_Collection_Types.html)
|
||||
更多关于字典(Dictionary)下标脚本的信息请参考[读取和修改字典](../chapter2/04_Collection_Types.html)
|
||||
|
||||
<<<<<<< HEAD
|
||||
> 注意:
|
||||
> Swift 中字典的附属脚本实现中,在`get`部分返回值是`Int?`,上例中的`numberOfLegs`字典通过附属脚本返回的是一个`Int?`或者说“可选的int”,不是每个字典的索引都能得到一个整型值,对于没有设过值的索引的访问返回的结果就是`nil`;同样想要从字典实例中删除某个索引下的值也只需要给这个索引赋值为`nil`即可。
|
||||
=======
|
||||
> 注意:
|
||||
>
|
||||
> Swift 中字典的下标脚本实现中,在`get`部分返回值是`Int?`,上例中的`numberOfLegs`字典通过下标脚本返回的是一个`Int?`或者说“可选的int”,不是每个字典的索引都能得到一个整型值,对于没有设过值的索引的访问返回的结果就是`nil`;同样想要从字典实例中删除某个索引下的值也只需要给这个索引赋值为`nil`即可。
|
||||
>>>>>>> a516af6a531a104ec88da0d236ecf389a5ec72af
|
||||
|
||||
<a name="subscript_options"></a>
|
||||
## 附属脚本选项
|
||||
## 下标脚本选项
|
||||
|
||||
附属脚本允许任意数量的入参索引,并且每个入参类型也没有限制。附属脚本的返回值也可以是任何类型。附属脚本可以使用变量参数和可变参数,但使用写入读出(in-out)参数或给参数设置默认值都是不允许的。
|
||||
下标脚本允许任意数量的入参索引,并且每个入参类型也没有限制。下标脚本的返回值也可以是任何类型。下标脚本可以使用变量参数和可变参数,但使用写入读出(in-out)参数或给参数设置默认值都是不允许的。
|
||||
|
||||
一个类或结构体可以根据自身需要提供多个附属脚本实现,在定义附属脚本时通过入参个类型进行区分,使用附属脚本时会自动匹配合适的附属脚本实现运行,这就是*附属脚本的重载*。
|
||||
一个类或结构体可以根据自身需要提供多个下标脚本实现,在定义下标脚本时通过入参个类型进行区分,使用下标脚本时会自动匹配合适的下标脚本实现运行,这就是*下标脚本的重载*。
|
||||
|
||||
一个附属脚本入参是最常见的情况,但只要有合适的场景也可以定义多个附属脚本入参。如下例定义了一个`Matrix`结构体,将呈现一个`Double`类型的二维矩阵。`Matrix`结构体的附属脚本需要两个整型参数:
|
||||
一个下标脚本入参是最常见的情况,但只要有合适的场景也可以定义多个下标脚本入参。如下例定义了一个`Matrix`结构体,将呈现一个`Double`类型的二维矩阵。`Matrix`结构体的下标脚本需要两个整型参数:
|
||||
|
||||
```swift
|
||||
struct Matrix {
|
||||
@ -138,7 +154,7 @@ row0 [0.0, 0.0,
|
||||
row1 0.0, 0.0]
|
||||
```
|
||||
|
||||
将值赋给带有`row`和`column`附属脚本的`matrix`实例表达式可以完成赋值操作,附属脚本入参使用逗号分割
|
||||
将值赋给带有`row`和`column`下标脚本的`matrix`实例表达式可以完成赋值操作,下标脚本入参使用逗号分割
|
||||
|
||||
```swift
|
||||
matrix[0, 1] = 1.5
|
||||
@ -152,7 +168,7 @@ matrix[1, 0] = 3.2
|
||||
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 {
|
||||
@ -160,7 +176,7 @@ func indexIsValidForRow(row: Int, column: Int) -> Bool {
|
||||
}
|
||||
```
|
||||
|
||||
断言在附属脚本越界时触发:
|
||||
断言在下标脚本越界时触发:
|
||||
|
||||
```swift
|
||||
let someValue = matrix[2, 2]
|
||||
|
||||
16
source/chapter2/13_Inheritance.md
Normal file → Executable file
16
source/chapter2/13_Inheritance.md
Normal file → Executable file
@ -13,7 +13,7 @@
|
||||
|
||||
一个类可以*继承(inherit)*另一个类的方法(methods),属性(property)和其它特性。当一个类继承其它类时,继承类叫*子类(subclass)*,被继承类叫*超类(或父类,superclass)*。在 Swift 中,继承是区分「类」与其它类型的一个基本特征。
|
||||
|
||||
在 Swift 中,类可以调用和访问超类的方法,属性和附属脚本(subscripts),并且可以重写(override)这些方法,属性和附属脚本来优化或修改它们的行为。Swift 会检查你的重写定义在超类中是否有匹配的定义,以此确保你的重写行为是正确的。
|
||||
在 Swift 中,类可以调用和访问超类的方法,属性和下标脚本(subscripts),并且可以重写(override)这些方法,属性和下标脚本来优化或修改它们的行为。Swift 会检查你的重写定义在超类中是否有匹配的定义,以此确保你的重写行为是正确的。
|
||||
|
||||
可以为类中继承来的属性添加属性观察器(property observer),这样一来,当属性值改变时,类就会被通知到。可以为任何属性添加属性观察器,无论它原本被定义为存储型属性(stored property)还是计算型属性(computed property)。
|
||||
|
||||
@ -137,21 +137,21 @@ println("Tandem: \(tandem.description())")
|
||||
<a name="overriding"></a>
|
||||
## 重写(Overriding)
|
||||
|
||||
子类可以为继承来的实例方法(instance method),类方法(class method),实例属性(instance property),或附属脚本(subscript)提供自己定制的实现(implementation)。我们把这种行为叫*重写(overriding)*。
|
||||
子类可以为继承来的实例方法(instance method),类方法(class method),实例属性(instance property),或下标脚本(subscript)提供自己定制的实现(implementation)。我们把这种行为叫*重写(overriding)*。
|
||||
|
||||
如果要重写某个特性,你需要在重写定义的前面加上`override`关键字。这么做,你就表明了你是想提供一个重写版本,而非错误地提供了一个相同的定义。意外的重写行为可能会导致不可预知的错误,任何缺少`override`关键字的重写都会在编译时被诊断为错误。
|
||||
|
||||
`override`关键字会提醒 Swift 编译器去检查该类的超类(或其中一个父类)是否有匹配重写版本的声明。这个检查可以确保你的重写定义是正确的。
|
||||
|
||||
### 访问超类的方法,属性及附属脚本
|
||||
### 访问超类的方法,属性及下标脚本
|
||||
|
||||
当你在子类中重写超类的方法,属性或附属脚本时,有时在你的重写版本中使用已经存在的超类实现会大有裨益。比如,你可以优化已有实现的行为,或在一个继承来的变量中存储一个修改过的值。
|
||||
当你在子类中重写超类的方法,属性或下标脚本时,有时在你的重写版本中使用已经存在的超类实现会大有裨益。比如,你可以优化已有实现的行为,或在一个继承来的变量中存储一个修改过的值。
|
||||
|
||||
在合适的地方,你可以通过使用`super`前缀来访问超类版本的方法,属性或附属脚本:
|
||||
在合适的地方,你可以通过使用`super`前缀来访问超类版本的方法,属性或下标脚本:
|
||||
|
||||
* 在方法`someMethod`的重写实现中,可以通过`super.someMethod()`来调用超类版本的`someMethod`方法。
|
||||
* 在属性`someProperty`的 getter 或 setter 的重写实现中,可以通过`super.someProperty`来访问超类版本的`someProperty`属性。
|
||||
* 在附属脚本的重写实现中,可以通过`super[someIndex]`来访问超类版本中的相同附属脚本。
|
||||
* 在下标脚本的重写实现中,可以通过`super[someIndex]`来访问超类版本中的相同下标脚本。
|
||||
|
||||
### 重写方法
|
||||
|
||||
@ -262,9 +262,9 @@ println("AutomaticCar: \(automatic.description())")
|
||||
<a name="preventing_overrides"></a>
|
||||
## 防止重写
|
||||
|
||||
你可以通过把方法,属性或附属脚本标记为*`final`*来防止它们被重写,只需要在声明关键字前加上`@final`特性即可。(例如:`@final var`, `@final func`, `@final class func`, 以及 `@final subscript`)
|
||||
你可以通过把方法,属性或下标脚本标记为*`final`*来防止它们被重写,只需要在声明关键字前加上`@final`特性即可。(例如:`@final var`, `@final func`, `@final class func`, 以及 `@final subscript`)
|
||||
|
||||
如果你重写了`final`方法,属性或附属脚本,在编译时会报错。在扩展中,你添加到类里的方法,属性或附属脚本也可以在扩展的定义里标记为 final。
|
||||
如果你重写了`final`方法,属性或下标脚本,在编译时会报错。在扩展中,你添加到类里的方法,属性或下标脚本也可以在扩展的定义里标记为 final。
|
||||
|
||||
你可以通过在关键字`class`前添加`@final`特性(`@final class`)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。
|
||||
|
||||
|
||||
0
source/chapter2/14_Initialization.md
Normal file → Executable file
0
source/chapter2/14_Initialization.md
Normal file → Executable file
0
source/chapter2/15_Deinitialization.md
Normal file → Executable file
0
source/chapter2/15_Deinitialization.md
Normal file → Executable file
6
source/chapter2/16_Automatic_Reference_Counting.md
Normal file → Executable file
6
source/chapter2/16_Automatic_Reference_Counting.md
Normal file → Executable file
@ -274,7 +274,7 @@ Swift 提供了两种办法用来解决你在使用类的属性时所遇到的
|
||||
john = Customer(name: "John Appleseed")
|
||||
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
|
||||
|
||||
在你关联两个实例后,他们的引用关系如下图所示:
|
||||
在你关联两个实例后,它们的引用关系如下图所示:
|
||||
|
||||

|
||||
|
||||
@ -329,7 +329,7 @@ Swift 提供了两种办法用来解决你在使用类的属性时所遇到的
|
||||
|
||||
`Country`的构造函数调用了`City`的构造函数。然而,只有`Country`的实例完全初始化完后,`Country`的构造函数才能把`self`传给`City`的构造函数。([在两段式构造过程中有具体描述](14_Initialization.html))
|
||||
|
||||
为了满足这种需求,通过在类型结尾处加上感叹号(City!)的方式,将`Country`的`capitalCity`属性声明为隐式解析可选类型的属性。这表示像其他可选类型一样,`capitalCity`属性的默认值为`nil`,但是不需要展开他的值就能访问它。([在隐式解析可选类型中有描述](01_The_Basics.html))
|
||||
为了满足这种需求,通过在类型结尾处加上感叹号(City!)的方式,将`Country`的`capitalCity`属性声明为隐式解析可选类型的属性。这表示像其他可选类型一样,`capitalCity`属性的默认值为`nil`,但是不需要展开它的值就能访问它。([在隐式解析可选类型中有描述](01_The_Basics.html))
|
||||
|
||||
由于`capitalCity`默认值为`nil`,一旦`Country`的实例在构造函数中给`name`属性赋值后,整个初始化过程就完成了。这代表一旦`name`属性被赋值后,`Country`的构造函数就能引用并传递隐式的`self`。`Country`的构造函数在赋值`capitalCity`时,就能将`self`作为参数传递给`City`的构造函数。
|
||||
|
||||
@ -449,7 +449,7 @@ Swift 有如下要求:只要在闭包内使用`self`的成员,就要用`self
|
||||
|
||||
当闭包和捕获的实例总是互相引用时并且总是同时销毁时,将闭包内的捕获定义为无主引用。
|
||||
|
||||
相反的,当捕获引用有时可能会是`nil`时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为`nil`。这使我们可以在闭包内检查他们是否存在。
|
||||
相反的,当捕获引用有时可能会是`nil`时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为`nil`。这使我们可以在闭包内检查它们是否存在。
|
||||
|
||||
>注意:
|
||||
>
|
||||
|
||||
4
source/chapter2/17_Optional_Chaining.md
Normal file → Executable file
4
source/chapter2/17_Optional_Chaining.md
Normal file → Executable file
@ -24,7 +24,7 @@ Swift 的可选链和 Objective-C 中的消息为空有些相像,但是 Swift
|
||||
<a name="optional_chaining_as_an_alternative_to_forced_unwrapping"></a>
|
||||
## 可选链可替代强制解析
|
||||
|
||||
通过在想调用的属性、方法、或子脚本的可选值(`optional value`)(非空)后面放一个问号,可以定义一个可选链。这一点很像在可选值后面放一个叹号来强制拆得其封包内的值。他们的主要的区别在于当可选值为空时可选链即刻失败,然而一般的强制解析将会引发运行时错误。
|
||||
通过在想调用的属性、方法、或子脚本的可选值(`optional value`)(非空)后面放一个问号,可以定义一个可选链。这一点很像在可选值后面放一个叹号来强制拆得其封包内的值。它们的主要的区别在于当可选值为空时可选链即刻失败,然而一般的强制解析将会引发运行时错误。
|
||||
|
||||
为了反映可选链可以调用空(`nil`),不论你调用的属性、方法、子脚本等返回的值是不是可选值,它的返回结果都是一个可选值。你可以利用这个返回值来检测你的可选链是否调用成功,有返回值即成功,返回nil则失败。
|
||||
|
||||
@ -232,7 +232,7 @@ Swift 的可选链和 Objective-C 中的消息为空有些相像,但是 Swift
|
||||
如果你试图通过可选链获得`Int`值,不论使用了多少层链接返回的总是`Int?`。
|
||||
相似的,如果你试图通过可选链获得`Int?`值,不论使用了多少层链接返回的总是`Int?`。
|
||||
|
||||
下面的例子试图获取`john`的`residence`属性里的`address`的`street`属性。这里使用了两层可选链来联系`residence`和`address`属性,他们两者都是可选类型:
|
||||
下面的例子试图获取`john`的`residence`属性里的`address`的`street`属性。这里使用了两层可选链来联系`residence`和`address`属性,它们两者都是可选类型:
|
||||
|
||||
if let johnsStreet = john.residence?.address?.street {
|
||||
println("John's street name is \(johnsStreet).")
|
||||
|
||||
0
source/chapter2/18_Type_Casting.md
Normal file → Executable file
0
source/chapter2/18_Type_Casting.md
Normal file → Executable file
0
source/chapter2/19_Nested_Types.md
Normal file → Executable file
0
source/chapter2/19_Nested_Types.md
Normal file → Executable file
4
source/chapter2/20_Extensions.md
Normal file → Executable file
4
source/chapter2/20_Extensions.md
Normal file → Executable file
@ -23,7 +23,7 @@ Swift 中的扩展可以:
|
||||
- 提供新的构造器
|
||||
- 定义下标
|
||||
- 定义和使用新的嵌套类型
|
||||
- 使一个已有类型符合某个接口
|
||||
- 使一个已有类型符合某个协议
|
||||
|
||||
|
||||
>注意:
|
||||
@ -41,7 +41,7 @@ extension SomeType {
|
||||
}
|
||||
```
|
||||
|
||||
一个扩展可以扩展一个已有类型,使其能够适配一个或多个协议(protocol)。当这种情况发生时,接口的名字应该完全按照类或结构体的名字的方式进行书写:
|
||||
一个扩展可以扩展一个已有类型,使其能够适配一个或多个协议(protocol)。当这种情况发生时,协议的名字应该完全按照类或结构体的名字的方式进行书写:
|
||||
|
||||
```
|
||||
extension SomeType: SomeProtocol, AnotherProctocol {
|
||||
|
||||
2
source/chapter2/21_Protocols.md
Normal file → Executable file
2
source/chapter2/21_Protocols.md
Normal file → Executable file
@ -525,7 +525,7 @@
|
||||
init(legs: Int) { self.legs = legs }
|
||||
}
|
||||
|
||||
`Circle,Country,Animal`并没有一个相同的基类,所以采用`AnyObject`类型的数组来装载在他们的实例,如下所示:
|
||||
`Circle,Country,Animal`并没有一个相同的基类,所以采用`AnyObject`类型的数组来装载在它们的实例,如下所示:
|
||||
|
||||
let objects: AnyObject[] = [
|
||||
Circle(radius: 2.0),
|
||||
|
||||
14
source/chapter2/22_Generics.md
Normal file → Executable file
14
source/chapter2/22_Generics.md
Normal file → Executable file
@ -155,7 +155,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
这个结构体在栈中使用一个`Array`性质的`items`存储值。`Stack`提供两个方法:`push`和`pop`,从栈中压进一个值和移除一个值。这些方法标记为可变的,因为他们需要修改(或*转换*)结构体的`items`数组。
|
||||
这个结构体在栈中使用一个`Array`性质的`items`存储值。`Stack`提供两个方法:`push`和`pop`,从栈中压进一个值和移除一个值。这些方法标记为可变的,因为它们需要修改(或*转换*)结构体的`items`数组。
|
||||
|
||||
上面所展现的`IntStack`类型只能用于`Int`值,不过,其对于定义一个泛型`Stack`类(可以处理*任何*类型值的栈)是非常有用的。
|
||||
|
||||
@ -213,7 +213,7 @@
|
||||
|
||||
这个需求强制加上一个类型约束作用于`Dictionary`的键上,当然其键类型必须遵循`Hashable`协议(Swift 标准库中定义的一个特定协议)。所有的 Swift 基本类型(如`String`,`Int`, `Double`和 `Bool`)默认都是可哈希。
|
||||
|
||||
当你创建自定义泛型类型时,你可以定义你自己的类型约束,当然,这些约束要支持泛型编程的强力特征中的多数。抽象概念如`可哈希`具有的类型特征是根据他们概念特征来界定的,而不是他们的直接类型特征。
|
||||
当你创建自定义泛型类型时,你可以定义你自己的类型约束,当然,这些约束要支持泛型编程的强力特征中的多数。抽象概念如`可哈希`具有的类型特征是根据它们概念特征来界定的,而不是它们的直接类型特征。
|
||||
|
||||
### 类型约束语法
|
||||
|
||||
@ -391,7 +391,7 @@ Swift的`Array`已经提供`append`方法,一个`count`属性和通过下标
|
||||
|
||||
下面的列子定义了一个名为`allItemsMatch`的泛型函数,用来检查是否两个`Container`单例包含具有相同顺序的相同元素。如果匹配到所有的元素,那么返回一个为`true`的`Boolean`值,反之,则相反。
|
||||
|
||||
这两个容器可以被检查出是否是相同类型的容器(虽然它们可以是),但他们确实拥有相同类型的元素。这个需求通过一个类型约束和`where`语句结合来表示:
|
||||
这两个容器可以被检查出是否是相同类型的容器(虽然它们可以是),但它们确实拥有相同类型的元素。这个需求通过一个类型约束和`where`语句结合来表示:
|
||||
|
||||
func allItemsMatch<
|
||||
C1: Container, C2: Container
|
||||
@ -434,11 +434,11 @@ Swift的`Array`已经提供`append`方法,一个`count`属性和通过下标
|
||||
`someContainer`和`anotherContainer`包含相同的元素类型。
|
||||
`someContainer`中的元素可以通过不等于操作(`!=`)来检查它们是否彼此不同。
|
||||
|
||||
第三个和第四个要求结合起来的意思是`anotherContainer`中的元素也可以通过 `!=` 操作来检查,因为他们在`someContainer`中元素确实是相同的类型。
|
||||
第三个和第四个要求结合起来的意思是`anotherContainer`中的元素也可以通过 `!=` 操作来检查,因为它们在`someContainer`中元素确实是相同的类型。
|
||||
|
||||
这些要求能够使`allItemsMatch`函数比较两个容器,即便他们是不同的容器类型。
|
||||
这些要求能够使`allItemsMatch`函数比较两个容器,即便它们是不同的容器类型。
|
||||
|
||||
`allItemsMatch`首先检查两个容器是否拥有同样数目的items,如果他们的元素数目不同,没有办法进行匹配,函数就会`false`。
|
||||
`allItemsMatch`首先检查两个容器是否拥有同样数目的items,如果它们的元素数目不同,没有办法进行匹配,函数就会`false`。
|
||||
|
||||
检查完之后,函数通过`for-in`循环和半闭区间操作(..)来迭代`someContainer`中的所有元素。对于每个元素,函数检查是否`someContainer`中的元素不等于对应的`anotherContainer`中的元素,如果这两个元素不等,则这两个容器不匹配,返回`false`。
|
||||
|
||||
@ -460,7 +460,7 @@ Swift的`Array`已经提供`append`方法,一个`count`属性和通过下标
|
||||
}
|
||||
// 输出 "All items match."
|
||||
|
||||
上面的例子创建一个`Stack`单例来存储`String`,然后压了三个字符串进栈。这个例子也创建了一个`Array`单例,并初始化包含三个同栈里一样的原始字符串。即便栈和数组否是不同的类型,但他们都遵循`Container`协议,而且他们都包含同样的类型值。你因此可以调用`allItemsMatch`函数,用这两个容器作为它的参数。在上面的例子中,`allItemsMatch`函数正确的显示了所有的这两个容器的`items`匹配。
|
||||
上面的例子创建一个`Stack`单例来存储`String`,然后压了三个字符串进栈。这个例子也创建了一个`Array`单例,并初始化包含三个同栈里一样的原始字符串。即便栈和数组否是不同的类型,但它们都遵循`Container`协议,而且它们都包含同样的类型值。你因此可以调用`allItemsMatch`函数,用这两个容器作为它的参数。在上面的例子中,`allItemsMatch`函数正确的显示了所有的这两个容器的`items`匹配。
|
||||
|
||||
[1]: ../chapter2/06_Functions.html
|
||||
[2]: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/stackPushPop_2x.png
|
||||
|
||||
4
source/chapter2/23_Advanced_Operators.md
Normal file → Executable file
4
source/chapter2/23_Advanced_Operators.md
Normal file → Executable file
@ -426,7 +426,7 @@ Swift无所知道自定义类型是否相等或不等,因为等于或者不等
|
||||
}
|
||||
```
|
||||
|
||||
上述代码实现了相等运算符`==`来判断两个`Vector2D`对象是否有相等的值,相等的概念就是他们有相同的`x`值和相同的`y`值,我们就用这个逻辑来实现。接着使用`==`的结果实现了不相等运算符`!=`。
|
||||
上述代码实现了相等运算符`==`来判断两个`Vector2D`对象是否有相等的值,相等的概念就是它们有相同的`x`值和相同的`y`值,我们就用这个逻辑来实现。接着使用`==`的结果实现了不相等运算符`!=`。
|
||||
|
||||
现在我们可以使用这两个运算符来判断两个`Vector2D`对象是否相等。
|
||||
|
||||
@ -489,4 +489,4 @@ let plusMinusVector = firstVector +- secondVector
|
||||
// plusMinusVector 此时的值为 (4.0, -2.0)
|
||||
```
|
||||
|
||||
这个运算符把两个向量的`x`相加,把向量的`y`相减。因为他实际是属于加减运算,所以让它保持了和加法一样的结合性和优先级(`left`和`140`)。查阅完整的Swift默认结合性和优先级的设置,请移步[表达式](../chapter3/04_Expressions.html);
|
||||
这个运算符把两个向量的`x`相加,把向量的`y`相减。因为它实际是属于加减运算,所以让它保持了和加法一样的结合性和优先级(`left`和`140`)。查阅完整的Swift默认结合性和优先级的设置,请移步[表达式](../chapter3/04_Expressions.html);
|
||||
|
||||
0
source/chapter2/chapter2.md
Normal file → Executable file
0
source/chapter2/chapter2.md
Normal file → Executable file
Reference in New Issue
Block a user