去除行末冗余空格

This commit is contained in:
bqlin
2018-02-14 19:53:19 +08:00
parent ad1d3944bc
commit 34f8d0c6b9
27 changed files with 264 additions and 264 deletions

View File

@ -43,7 +43,7 @@ print("Hello, world!")
这个教程会通过一系列编程例子来让你对 Swift 有初步了解,如果你有什么不理解的地方也不用担心——任何本章介绍的内容都会在后面的章节中详细讲解到。 这个教程会通过一系列编程例子来让你对 Swift 有初步了解,如果你有什么不理解的地方也不用担心——任何本章介绍的内容都会在后面的章节中详细讲解到。
> 注意: > 注意:
> 在 Mac 中下载 Playground 文件并用双击的方式在 Xcode 中打开:[https://developer.apple.com/go/?id=swift-tour](https://developer.apple.com/go/?id=swift-tour) > 在 Mac 中下载 Playground 文件并用双击的方式在 Xcode 中打开:[https://developer.apple.com/go/?id=swift-tour](https://developer.apple.com/go/?id=swift-tour)
<a name="simple_values"></a> <a name="simple_values"></a>
@ -67,7 +67,7 @@ let implicitDouble = 70.0
let explicitDouble: Double = 70 let explicitDouble: Double = 70
``` ```
> 练习: > 练习:
> 创建一个常量,显式指定类型为 `Float` 并指定初始值为 4。 > 创建一个常量,显式指定类型为 `Float` 并指定初始值为 4。
值永远不会被隐式转换为其他类型。如果你需要把一个值转换成其他类型,请显式转换。 值永远不会被隐式转换为其他类型。如果你需要把一个值转换成其他类型,请显式转换。
@ -77,7 +77,7 @@ let label = "The width is"
let width = 94 let width = 94
let widthLabel = label + String(width) let widthLabel = label + String(width)
``` ```
> 练习: > 练习:
> 删除最后一行中的 `String`,错误提示是什么? > 删除最后一行中的 `String`,错误提示是什么?
有一种更简单的把值转换成字符串的方法:把值写到括号中,并且在括号之前写一个反斜杠(\)。例如: 有一种更简单的把值转换成字符串的方法:把值写到括号中,并且在括号之前写一个反斜杠(\)。例如:
@ -89,7 +89,7 @@ let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit." let fruitSummary = "I have \(apples + oranges) pieces of fruit."
``` ```
> 练习: > 练习:
> 使用 `\()` 来把一个浮点计算转换成字符串,并加上某人的名字,和他打个招呼。 > 使用 `\()` 来把一个浮点计算转换成字符串,并加上某人的名字,和他打个招呼。
使用一对三个单引号(`"""`)来包含多行字符串内容,字符串中的内容(包括引号、空格、换行符等)都会保留下来。举个例子: 使用一对三个单引号(`"""`)来包含多行字符串内容,字符串中的内容(包括引号、空格、换行符等)都会保留下来。举个例子:
@ -165,11 +165,11 @@ if let name = optionalName {
} }
``` ```
> 练习: > 练习:
> 把 `optionalName` 改成 `nil`greeting 会是什么?添加一个 `else` 语句,当 `optionalName` 是 `nil` 时给 greeting 赋一个不同的值。 > 把 `optionalName` 改成 `nil`greeting 会是什么?添加一个 `else` 语句,当 `optionalName` 是 `nil` 时给 greeting 赋一个不同的值。
如果变量的可选值是 `nil`,条件会判断为 `false`,大括号中的代码会被跳过。如果不是 `nil`,会将值解包并赋给 `let` 后面的常量,这样代码块中就可以使用这个值了。 如果变量的可选值是 `nil`,条件会判断为 `false`,大括号中的代码会被跳过。如果不是 `nil`,会将值解包并赋给 `let` 后面的常量,这样代码块中就可以使用这个值了。
另一种处理可选值的方法是通过使用 `??` 操作符来提供一个默认值。如果可选值缺失的话,可以使用默认值来代替。 另一种处理可选值的方法是通过使用 `??` 操作符来提供一个默认值。如果可选值缺失的话,可以使用默认值来代替。
```swift ```swift
let nickName: String? = nil let nickName: String? = nil
@ -193,7 +193,7 @@ default:
} }
``` ```
> 练习: > 练习:
> 删除 `default` 语句,看看会有什么错误? > 删除 `default` 语句,看看会有什么错误?
注意 `let` 在上述例子的等式中是如何使用的,它将匹配等式的值赋给常量 `x` 注意 `let` 在上述例子的等式中是如何使用的,它将匹配等式的值赋给常量 `x`
@ -219,7 +219,7 @@ for (kind, numbers) in interestingNumbers {
print(largest) print(largest)
``` ```
> 练习: > 练习:
> 添加另一个变量来记录最大数字的种类(kind),同时仍然记录这个最大数字的值。 > 添加另一个变量来记录最大数字的种类(kind),同时仍然记录这个最大数字的值。
使用 `while` 来重复运行一段代码直到条件改变。循环条件也可以在结尾,保证能至少循环一次。 使用 `while` 来重复运行一段代码直到条件改变。循环条件也可以在结尾,保证能至少循环一次。
@ -262,7 +262,7 @@ func greet(person: String, day: String) -> String {
greet(person:"Bob", day: "Tuesday") greet(person:"Bob", day: "Tuesday")
``` ```
> 练习: > 练习:
> 删除 `day` 参数,添加一个参数来表示今天吃了什么午饭。 > 删除 `day` 参数,添加一个参数来表示今天吃了什么午饭。
默认情况下,函数使用它们的参数名称作为它们参数的标签,在参数名称前可以自定义参数标签,或者使用 `_` 表示不使用参数标签。 默认情况下,函数使用它们的参数名称作为它们参数的标签,在参数名称前可以自定义参数标签,或者使用 `_` 表示不使用参数标签。
@ -353,7 +353,7 @@ numbers.map({
}) })
``` ```
> 练习: > 练习:
> 重写闭包,对所有奇数返回 0。 > 重写闭包,对所有奇数返回 0。
有很多种创建更简洁的闭包的方法。如果一个闭包的类型已知,比如作为一个代理的回调,你可以忽略参数,返回值,甚至两个都忽略。单个语句闭包会把它语句的值当做结果返回。 有很多种创建更简洁的闭包的方法。如果一个闭包的类型已知,比如作为一个代理的回调,你可以忽略参数,返回值,甚至两个都忽略。单个语句闭包会把它语句的值当做结果返回。
@ -384,7 +384,7 @@ class Shape {
} }
``` ```
> 练习: > 练习:
> 使用 `let` 添加一个常量属性,再添加一个接收一个参数的方法。 > 使用 `let` 添加一个常量属性,再添加一个接收一个参数的方法。
要创建一个类的实例,在类名后面加上括号。使用点语法来访问实例的属性和方法。 要创建一个类的实例,在类名后面加上括号。使用点语法来访问实例的属性和方法。
@ -443,7 +443,7 @@ test.area()
test.simpleDescription() test.simpleDescription()
``` ```
> 练习: > 练习:
> 创建 `NamedShape` 的另一个子类 `Circle`,构造器接收两个参数,一个是半径一个是名称,在子类 `Circle` 中实现 `area()` 和 `simpleDescription()` 方法。 > 创建 `NamedShape` 的另一个子类 `Circle`,构造器接收两个参数,一个是半径一个是名称,在子类 `Circle` 中实现 `area()` 和 `simpleDescription()` 方法。
除了储存简单的属性之外,属性可以有 getter 和 setter 。 除了储存简单的属性之外,属性可以有 getter 和 setter 。
@ -547,7 +547,7 @@ let ace = Rank.ace
let aceRawValue = ace.rawValue let aceRawValue = ace.rawValue
``` ```
> 练习: > 练习:
> 写一个函数,通过比较它们的原始值来比较两个 `Rank` 值。 > 写一个函数,通过比较它们的原始值来比较两个 `Rank` 值。
默认情况下Swift 按照从 0 开始每次加 1 的方式为原始值进行赋值,不过你可以通过显式赋值进行改变。在上面的例子中,`Ace` 被显式赋值为 1并且剩下的原始值会按照顺序赋值。你也可以使用字符串或者浮点数作为枚举的原始值。使用 `rawValue` 属性来访问一个枚举成员的原始值。 默认情况下Swift 按照从 0 开始每次加 1 的方式为原始值进行赋值,不过你可以通过显式赋值进行改变。在上面的例子中,`Ace` 被显式赋值为 1并且剩下的原始值会按照顺序赋值。你也可以使用字符串或者浮点数作为枚举的原始值。使用 `rawValue` 属性来访问一个枚举成员的原始值。
@ -582,7 +582,7 @@ let hearts = Suit.hearts
let heartsDescription = hearts.simpleDescription() let heartsDescription = hearts.simpleDescription()
``` ```
> 练习: > 练习:
> 给 `Suit` 添加一个 `color()` 方法,对 `spades` 和 `clubs` 返回 “black” ,对 `hearts` 和 `diamonds` 返回 “red” 。 > 给 `Suit` 添加一个 `color()` 方法,对 `spades` 和 `clubs` 返回 “black” ,对 `hearts` 和 `diamonds` 返回 “red” 。
注意在上面的例子中用了两种方式引用 `hearts` 枚举成员:给 `hearts` 常量赋值时,枚举成员 `Suit.hearts` 需要用全名来引用,因为常量没有显式指定类型。在 `switch` 里,枚举成员使用缩写 `.hearts` 来引用,因为 `self` 的值已经是一个 `suit` 类型,在已知变量类型的情况下可以使用缩写。 注意在上面的例子中用了两种方式引用 `hearts` 枚举成员:给 `hearts` 常量赋值时,枚举成员 `Suit.hearts` 需要用全名来引用,因为常量没有显式指定类型。在 `switch` 里,枚举成员使用缩写 `.hearts` 来引用,因为 `self` 的值已经是一个 `suit` 类型,在已知变量类型的情况下可以使用缩写。
@ -606,7 +606,7 @@ case let .failure(message):
} }
``` ```
> 练习: > 练习:
> 给 `ServerResponse` 和 switch 添加第三种情况。 > 给 `ServerResponse` 和 switch 添加第三种情况。
注意日升和日落时间是如何从 `ServerResponse` 中提取到并与 `switch``case` 相匹配的。 注意日升和日落时间是如何从 `ServerResponse` 中提取到并与 `switch``case` 相匹配的。
@ -625,7 +625,7 @@ let threeOfSpades = Card(rank: .three, suit: .spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription() let threeOfSpadesDescription = threeOfSpades.simpleDescription()
``` ```
> 练习: > 练习:
> 给 `Card` 添加一个方法,创建一副完整的扑克牌并把每张牌的 rank 和 suit 对应起来。 > 给 `Card` 添加一个方法,创建一副完整的扑克牌并把每张牌的 rank 和 suit 对应起来。
<a name="protocols_and_extensions"></a> <a name="protocols_and_extensions"></a>
@ -665,7 +665,7 @@ b.adjust()
let bDescription = b.simpleDescription let bDescription = b.simpleDescription
``` ```
> 练习: > 练习:
> 写一个实现这个协议的枚举。 > 写一个实现这个协议的枚举。
注意声明 `SimpleStructure` 时候 `mutating` 关键字用来标记一个会修改结构体的方法。`SimpleClass` 的声明不需要标记任何方法,因为类中的方法通常可以修改类属性(类的性质)。 注意声明 `SimpleStructure` 时候 `mutating` 关键字用来标记一个会修改结构体的方法。`SimpleClass` 的声明不需要标记任何方法,因为类中的方法通常可以修改类属性(类的性质)。
@ -684,7 +684,7 @@ extension Int: ExampleProtocol {
print(7.simpleDescription) print(7.simpleDescription)
``` ```
> 练习: > 练习:
> 给 `Double` 类型写一个扩展,添加 `absoluteValue` 属性。 > 给 `Double` 类型写一个扩展,添加 `absoluteValue` 属性。
你可以像使用其他命名类型一样使用协议名——例如,创建一个有不同类型但是都实现一个协议的对象集合。当你处理类型是协议的值时,协议外定义的方法不可用。 你可以像使用其他命名类型一样使用协议名——例如,创建一个有不同类型但是都实现一个协议的对象集合。当你处理类型是协议的值时,协议外定义的方法不可用。
@ -732,7 +732,7 @@ do {
} }
``` ```
> 练习: > 练习:
> 将 printer name 改为 `"Never Has Toner"` 使 `send(job:toPrinter:)` 函数抛出错误。 > 将 printer name 改为 `"Never Has Toner"` 使 `send(job:toPrinter:)` 函数抛出错误。
可以使用多个 `catch` 块来处理特定的错误。参照 switch 中的 `case` 风格来写 `catch` 可以使用多个 `catch` 块来处理特定的错误。参照 switch 中的 `case` 风格来写 `catch`
@ -750,7 +750,7 @@ do {
} }
``` ```
> 练习: > 练习:
> 在 `do` 代码块中添加抛出错误的代码。你需要抛出哪种错误来使第一个 `catch` 块进行接收?怎么使第二个和第三个 `catch` 进行接收呢? > 在 `do` 代码块中添加抛出错误的代码。你需要抛出哪种错误来使第一个 `catch` 块进行接收?怎么使第二个和第三个 `catch` 进行接收呢?
另一种处理错误的方式使用 `try?` 将结果转换为可选的。如果函数抛出错误,该错误会被抛弃并且结果为 `nil`。否则,结果会是一个包含函数返回值的可选值。 另一种处理错误的方式使用 `try?` 将结果转换为可选的。如果函数抛出错误,该错误会被抛弃并且结果为 `nil`。否则,结果会是一个包含函数返回值的可选值。
@ -824,7 +824,7 @@ func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
anyCommonElements([1, 2, 3], [3]) anyCommonElements([1, 2, 3], [3])
``` ```
> 练习: > 练习:
> 修改 `anyCommonElements(_:_:)` 函数来创建一个函数,返回一个数组,内容是两个序列的共有元素。 > 修改 `anyCommonElements(_:_:)` 函数来创建一个函数,返回一个数组,内容是两个序列的共有元素。
`<T: Equatable>``<T> ... where T: Equatable>` 的写法是等价的。 `<T: Equatable>``<T> ... where T: Equatable>` 的写法是等价的。

View File

@ -128,16 +128,16 @@
更新<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID546">逃逸闭包</a>一节,现在闭包默认为非逃逸的(noescaping)。 更新<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID546">逃逸闭包</a>一节,现在闭包默认为非逃逸的(noescaping)。
</li> </li>
<li> <li>
更新<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID309">基础部分</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID333">可选绑定</a>一节和<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID428">语句</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID432">While 语句</a>一节,现在 ifwhile 和 guard 语句使用逗号分隔条件列表,不需要使用 where 语句。 更新<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID309">基础部分</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID333">可选绑定</a>一节和<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID428">语句</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID432">While 语句</a>一节,现在 ifwhile 和 guard 语句使用逗号分隔条件列表,不需要使用 where 语句。
</li> </li>
<li> <li>
增加<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID120">控制流</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID129">Switch</a>一节和<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID428">语句</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID436">Switch 语句</a>一节关于 switch cases 可以使用多模式的信息。 增加<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID120">控制流</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID129">Switch</a>一节和<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID428">语句</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID436">Switch 语句</a>一节关于 switch cases 可以使用多模式的信息。
</li> </li>
<li> <li>
更新<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID449">函数类型</a>一节,现在函数参数标签不包含在函数类型中。 更新<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID449">函数类型</a>一节,现在函数参数标签不包含在函数类型中。
</li> </li>
<li> <li>
更新<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID267">协议</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID282">协议组合</a>一节和<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID445">类型</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID454">协议组合类型</a>一节关于使用新的 Protocol1 & Protocol2 语法的信息。 更新<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID267">协议</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID282">协议组合</a>一节和<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID445">类型</a>章节中<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID454">协议组合类型</a>一节关于使用新的 Protocol1 & Protocol2 语法的信息。
</li> </li>
<li> <li>
更新<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID402">动态类型表达式</a>一节使用新的 type(of:) 表达式的信息。 更新<a href="https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID402">动态类型表达式</a>一节使用新的 type(of:) 表达式的信息。
@ -345,7 +345,7 @@
<li> <li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID120">控制流</a>一章中a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID523">检查 API 可用性</a>一节和<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID428">语句</a>一章中<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID522">可用性条件</a>一节中关于 API 可用性检查的内容。 增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID120">控制流</a>一章中a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID523">检查 API 可用性</a>一节和<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID428">语句</a>一章中<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID522">可用性条件</a>一节中关于 API 可用性检查的内容。
</li> </li>
<li> <li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID120">控制流</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID525">早期退出</a>一节和<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID428">语句</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID524">guard语句</a>中关于新 <code>guard</code> 语句的内容。 增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID120">控制流</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID525">早期退出</a>一节和<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID428">语句</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID524">guard语句</a>中关于新 <code>guard</code> 语句的内容。
</li> </li>
@ -568,7 +568,7 @@
<li> <li>
自定义运算符现在可以包含`?`字符,更新的<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html">运算符(Operators)</a>章节描述了改进后的规则,并且从<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html">自定义运算符(Custom Operators)</a>章节删除了重复的运算符有效字符集合 自定义运算符现在可以包含`?`字符,更新的<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html">运算符(Operators)</a>章节描述了改进后的规则,并且从<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html">自定义运算符(Custom Operators)</a>章节删除了重复的运算符有效字符集合
</li> </li>
</ul> </ul>
</td> </td>
</tr> </tr>

View File

@ -92,7 +92,7 @@ var currentLoginAttempt = 0
var x = 0.0, y = 0.0, z = 0.0 var x = 0.0, y = 0.0, z = 0.0
``` ```
> 注意: > 注意:
> 如果你的代码中有不需要改变的值,请使用 `let` 关键字将它声明为常量。只将需要改变的值声明为变量。 > 如果你的代码中有不需要改变的值,请使用 `let` 关键字将它声明为常量。只将需要改变的值声明为变量。
<a name="type_annotations"></a> <a name="type_annotations"></a>
@ -124,7 +124,7 @@ welcomeMessage = "Hello"
var red, green, blue: Double var red, green, blue: Double
``` ```
> 注意: > 注意:
> 一般来说你很少需要写类型标注。如果你在声明常量或者变量的时候赋了一个初始值Swift可以推断出这个常量或者变量的类型请参考[类型安全和类型推断](#type_safety_and_type_inference)。在上面的例子中,没有给 `welcomeMessage` 赋初始值,所以变量 `welcomeMessage` 的类型是通过一个类型标注指定的,而不是通过初始值推断的。 > 一般来说你很少需要写类型标注。如果你在声明常量或者变量的时候赋了一个初始值Swift可以推断出这个常量或者变量的类型请参考[类型安全和类型推断](#type_safety_and_type_inference)。在上面的例子中,没有给 `welcomeMessage` 赋初始值,所以变量 `welcomeMessage` 的类型是通过一个类型标注指定的,而不是通过初始值推断的。
<a name="naming"></a> <a name="naming"></a>
@ -142,7 +142,7 @@ let 🐶🐮 = "dogcow"
一旦你将常量或者变量声明为确定的类型,你就不能使用相同的名字再次进行声明,或者改变其存储的值的类型。同时,你也不能将常量与变量进行互转。 一旦你将常量或者变量声明为确定的类型,你就不能使用相同的名字再次进行声明,或者改变其存储的值的类型。同时,你也不能将常量与变量进行互转。
> 注意: > 注意:
> 如果你需要使用与Swift保留关键字相同的名称作为常量或者变量名你可以使用反引号`)将关键字包围的方式将其作为名字使用。无论如何,你应当避免使用关键字作为常量或变量名,除非你别无选择。 > 如果你需要使用与Swift保留关键字相同的名称作为常量或者变量名你可以使用反引号`)将关键字包围的方式将其作为名字使用。无论如何,你应当避免使用关键字作为常量或变量名,除非你别无选择。
你可以更改现有的变量值为其他同类型的值,在下面的例子中,`friendlyWelcome`的值从`"Hello!"`改为了`"Bonjour!"`: 你可以更改现有的变量值为其他同类型的值,在下面的例子中,`friendlyWelcome`的值从`"Hello!"`改为了`"Bonjour!"`:
@ -180,7 +180,7 @@ print("The current value of friendlyWelcome is \(friendlyWelcome)")
// 输出 "The current value of friendlyWelcome is Bonjour! // 输出 "The current value of friendlyWelcome is Bonjour!
``` ```
> 注意: > 注意:
字符串插值所有可用的选项,请参考[字符串插值](./03_Strings_and_Characters.html#string_interpolation)。 字符串插值所有可用的选项,请参考[字符串插值](./03_Strings_and_Characters.html#string_interpolation)。
<a name="comments"></a> <a name="comments"></a>
@ -258,7 +258,7 @@ Swift 也提供了一个特殊的无符号类型 `UInt`,长度与当前平台
* 在32位平台上`UInt``UInt32` 长度相同。 * 在32位平台上`UInt``UInt32` 长度相同。
* 在64位平台上`UInt``UInt64` 长度相同。 * 在64位平台上`UInt``UInt64` 长度相同。
> 注意: > 注意:
尽量不要使用`UInt`,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用`Int`,即使你要存储的值已知是非负的。统一使用`Int`可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推断,请参考[类型安全和类型推断](#type_safety_and_type_inference)。 尽量不要使用`UInt`,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用`Int`,即使你要存储的值已知是非负的。统一使用`Int`可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推断,请参考[类型安全和类型推断](#type_safety_and_type_inference)。
<a name="floating-point_numbers"></a> <a name="floating-point_numbers"></a>
@ -271,7 +271,7 @@ Swift 也提供了一个特殊的无符号类型 `UInt`,长度与当前平台
* `Double`表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。 * `Double`表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。
* `Float`表示32位浮点数。精度要求不高的话可以使用此类型。 * `Float`表示32位浮点数。精度要求不高的话可以使用此类型。
> 注意: > 注意:
`Double`精确度很高至少有15位数字`Float`只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围在两种类型都匹配的情况下将优先选择 `Double` `Double`精确度很高至少有15位数字`Float`只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围在两种类型都匹配的情况下将优先选择 `Double`
<a name="type_safety_and_type_inference"></a> <a name="type_safety_and_type_inference"></a>
@ -415,7 +415,7 @@ let integerPi = Int(pi)
当用这种方式来初始化一个新的整数值时,浮点值会被截断。也就是说 `4.75` 会变成 `4``-3.9` 会变成 `-3` 当用这种方式来初始化一个新的整数值时,浮点值会被截断。也就是说 `4.75` 会变成 `4``-3.9` 会变成 `-3`
> 注意: > 注意:
结合数字类常量和变量不同于结合数字类字面量。字面量`3`可以直接和字面量`0.14159`相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测。 结合数字类常量和变量不同于结合数字类字面量。字面量`3`可以直接和字面量`0.14159`相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测。
<a name="type_aliases"></a> <a name="type_aliases"></a>
@ -545,7 +545,7 @@ print("The status message is \(http200Status.description)")
作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个 `(Int, String)` 元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考[函数参数与返回值](./06_Functions.html#Function_Parameters_and_Return_Values)。 作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个 `(Int, String)` 元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考[函数参数与返回值](./06_Functions.html#Function_Parameters_and_Return_Values)。
> 注意: > 注意:
元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组。请参考[类和结构体](./09_Classes_and_Structures.html)。 元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组。请参考[类和结构体](./09_Classes_and_Structures.html)。
<a name="optionals"></a> <a name="optionals"></a>
@ -559,7 +559,7 @@ print("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 的 `Int` 类型有一种构造器,作用是将一个 `String` 值转换成一个 `Int` 值。然而,并不是所有的字符串都可以转换成一个整数。字符串 `"123"` 可以被转换成数字 `123` ,但是字符串 `"hello, world"` 不行。 来看一个例子。Swift 的 `Int` 类型有一种构造器,作用是将一个 `String` 值转换成一个 `Int` 值。然而,并不是所有的字符串都可以转换成一个整数。字符串 `"123"` 可以被转换成数字 `123` ,但是字符串 `"hello, world"` 不行。
@ -586,7 +586,7 @@ serverResponseCode = nil
// serverResponseCode 现在不包含值 // serverResponseCode 现在不包含值
``` ```
> 注意: > 注意:
`nil`不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失的情况,请把它们声明成对应的可选类型。 `nil`不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失的情况,请把它们声明成对应的可选类型。
如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为 `nil` 如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为 `nil`
@ -596,7 +596,7 @@ var surveyAnswer: String?
// surveyAnswer 被自动设置为 nil // surveyAnswer 被自动设置为 nil
``` ```
> 注意: > 注意:
Swift 的 `nil` 和 Objective-C 中的 `nil` 并不一样。在 Objective-C 中,`nil` 是一个指向不存在对象的指针。在 Swift 中,`nil` 不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选状态都可以被设置为 `nil`,不只是对象类型。 Swift 的 `nil` 和 Objective-C 中的 `nil` 并不一样。在 Objective-C 中,`nil` 是一个指向不存在对象的指针。在 Swift 中,`nil` 不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选状态都可以被设置为 `nil`,不只是对象类型。
<a name="if"></a> <a name="if"></a>
@ -624,7 +624,7 @@ if convertedNumber != nil {
更多关于 `if` 语句的内容,请参考[控制流](05_Control_Flow.html)。 更多关于 `if` 语句的内容,请参考[控制流](05_Control_Flow.html)。
> 注意: > 注意:
使用 `!` 来获取一个不存在的可选值会导致运行时错误。使用 `!` 来强制解析值之前,一定要确定可选包含一个非 `nil` 的值。 使用 `!` 来获取一个不存在的可选值会导致运行时错误。使用 `!` 来强制解析值之前,一定要确定可选包含一个非 `nil` 的值。
<a name="optional_binding"></a> <a name="optional_binding"></a>
@ -703,7 +703,7 @@ let implicitString: String = assumedString // 不需要感叹号
你可以把隐式解析可选类型当做一个可以自动解析的可选类型。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。 你可以把隐式解析可选类型当做一个可以自动解析的可选类型。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。
> 注意: > 注意:
> 如果你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一个惊叹号一样。 > 如果你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一个惊叹号一样。
你仍然可以把隐式解析可选类型当做普通可选类型来判断它是否包含值: 你仍然可以把隐式解析可选类型当做普通可选类型来判断它是否包含值:
@ -724,7 +724,7 @@ if let definiteString = assumedString {
// 输出 "An implicitly unwrapped optional string." // 输出 "An implicitly unwrapped optional string."
``` ```
> 注意: > 注意:
> 如果一个变量之后可能变成`nil`的话请不要使用隐式解析可选类型。如果你需要在变量的生命周期中判断是否是`nil`的话,请使用普通可选类型。 > 如果一个变量之后可能变成`nil`的话请不要使用隐式解析可选类型。如果你需要在变量的生命周期中判断是否是`nil`的话,请使用普通可选类型。
<a name="error_handling"></a> <a name="error_handling"></a>
@ -834,6 +834,6 @@ precondition(index > 0, "Index must be greater than zero.")
你可以调用 `precondition(_:_:file:line:)`方法来表明出现了一个错误例如switch 进入了 default 分支,但是所有的有效值应该被任意一个其他分支(非 default 分支)处理。 你可以调用 `precondition(_:_:file:line:)`方法来表明出现了一个错误例如switch 进入了 default 分支,但是所有的有效值应该被任意一个其他分支(非 default 分支)处理。
> 注意: > 注意:
> 如果你使用unchecked模式-Ounchecked编译代码先决条件将不会进行检查。编译器假设所有的先决条件总是为true他将优化你的代码。然而`fatalError(_:file:line:)`函数总是中断执行,无论你怎么进行优化设定。 > 如果你使用unchecked模式-Ounchecked编译代码先决条件将不会进行检查。编译器假设所有的先决条件总是为true他将优化你的代码。然而`fatalError(_:file:line:)`函数总是中断执行,无论你怎么进行优化设定。
>你能使用 `fatalError(_:file:line:)`函数在设计原型和早期开发阶段这个阶段只有方法的声明但是没有具体实现你可以在方法体中写上fatalError("Unimplemented")作为具体实现。因为fatalError不会像断言和先决条件那样被优化掉所以你可以确保当代码执行到一个没有被实现的方法时程序会被中断。 >你能使用 `fatalError(_:file:line:)`函数在设计原型和早期开发阶段这个阶段只有方法的声明但是没有具体实现你可以在方法体中写上fatalError("Unimplemented")作为具体实现。因为fatalError不会像断言和先决条件那样被优化掉所以你可以确保当代码执行到一个没有被实现的方法时程序会被中断。

View File

@ -12,7 +12,7 @@
> 校对:[shanks](http://codebuild.me) > 校对:[shanks](http://codebuild.me)
> 2.2 > 2.2
> 翻译+校对:[Cee](https://github.com/Cee) 校对:[SketchK](https://github.com/SketchK)2016-05-11 > 翻译+校对:[Cee](https://github.com/Cee) 校对:[SketchK](https://github.com/SketchK)2016-05-11
> 3.0.1shanks2016-11-11 > 3.0.1shanks2016-11-11
> 4.0 > 4.0
@ -107,7 +107,7 @@ Swift 中所有数值类型都支持了基本的四则*算术运算符*
*求余运算符*`a % b`)是计算 `b` 的多少倍刚刚好可以容入`a`,返回多出来的那部分(余数)。 *求余运算符*`a % b`)是计算 `b` 的多少倍刚刚好可以容入`a`,返回多出来的那部分(余数)。
> 注意: > 注意:
求余运算符(`%`)在其他语言也叫*取模运算符*。但是严格说来,我们看该运算符对负数的操作结果,「求余」比「取模」更合适些。 求余运算符(`%`)在其他语言也叫*取模运算符*。但是严格说来,我们看该运算符对负数的操作结果,「求余」比「取模」更合适些。
我们来谈谈取余是怎么回事,计算 `9 % 4`,你先计算出 `4` 的多少倍会刚好可以容入 `9` 中: 我们来谈谈取余是怎么回事,计算 `9 % 4`,你先计算出 `4` 的多少倍会刚好可以容入 `9` 中:
@ -182,7 +182,7 @@ a += 2
表达式 `a += 2``a = a + 2` 的简写,一个组合加运算就是把加法运算和赋值运算组合成进一个运算符里,同时完成两个运算任务。 表达式 `a += 2``a = a + 2` 的简写,一个组合加运算就是把加法运算和赋值运算组合成进一个运算符里,同时完成两个运算任务。
> 注意: > 注意:
复合赋值运算没有返回值,`let b = a += 2`这类代码是错误。这不同于上面提到的自增和自减运算符。 复合赋值运算没有返回值,`let b = a += 2`这类代码是错误。这不同于上面提到的自增和自减运算符。
更多 Swift 标准库运算符的信息,请看[运算符声明](https://developer.apple.com/documentation/swift/operator_declarations)。 更多 Swift 标准库运算符的信息,请看[运算符声明](https://developer.apple.com/documentation/swift/operator_declarations)。
@ -244,7 +244,7 @@ if name == "world" {
("blue", false) < ("purple", true) // 错误,因为 < 不能比较布尔类型 ("blue", false) < ("purple", true) // 错误,因为 < 不能比较布尔类型
``` ```
>注意: >注意:
Swift 标准库只能比较七个以内元素的元组比较函数。如果你的元组元素超过七个时,你需要自己实现比较运算符。 Swift 标准库只能比较七个以内元素的元组比较函数。如果你的元组元素超过七个时,你需要自己实现比较运算符。
<a name="ternary_conditional_operator"></a> <a name="ternary_conditional_operator"></a>

View File

@ -16,7 +16,7 @@
> 校对:[SketchK](https://github.com/SketchK) > 校对:[SketchK](https://github.com/SketchK)
> 3.0 > 3.0
> 校对:[CMB](https://github.com/chenmingbiao)版本日期2016-09-13 > 校对:[CMB](https://github.com/chenmingbiao)版本日期2016-09-13
> 3.0.1, shanks, 2016-11-11 > 3.0.1, shanks, 2016-11-11
> 4.0 > 4.0
@ -41,15 +41,15 @@
*字符串*是例如`"hello, world"``"albatross"`这样的有序的`Character`(字符)类型的值的集合。通过`String`类型来表示。 *字符串*是例如`"hello, world"``"albatross"`这样的有序的`Character`(字符)类型的值的集合。通过`String`类型来表示。
一个`String`的内容可以用许多方式读取,包括作为一个`Character`值的集合。 一个`String`的内容可以用许多方式读取,包括作为一个`Character`值的集合。
Swift 的`String``Character`类型提供了快速和兼容 Unicode 的方式供你的代码使用。创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。 Swift 的`String``Character`类型提供了快速和兼容 Unicode 的方式供你的代码使用。创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。
字符串连接操作只需要简单地通过`+`符号将两个字符串相连即可。与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。你也可以在字符串内插过程中使用字符串插入常量、变量、字面量表达成更长的字符串,这样可以很容易的创建自定义的字符串值,进行展示、存储以及打印。 字符串连接操作只需要简单地通过`+`符号将两个字符串相连即可。与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。你也可以在字符串内插过程中使用字符串插入常量、变量、字面量表达成更长的字符串,这样可以很容易的创建自定义的字符串值,进行展示、存储以及打印。
尽管语法简易,但`String`类型是一种快速、现代化的字符串实现。 尽管语法简易,但`String`类型是一种快速、现代化的字符串实现。
每一个字符串都是由编码无关的 Unicode 字符组成,并支持访问字符的多种 Unicode 表示形式representations 每一个字符串都是由编码无关的 Unicode 字符组成,并支持访问字符的多种 Unicode 表示形式representations
> 注意: > 注意:
> Swift 的`String`类型与 Foundation `NSString`类进行了无缝桥接。Foundation 也可以对`String`进行扩展,暴露在`NSString`中定义的方法。 这意味着,如果你在`String`中调用这些`NSString`的方法,将不用进行转换。 > Swift 的`String`类型与 Foundation `NSString`类进行了无缝桥接。Foundation 也可以对`String`进行扩展,暴露在`NSString`中定义的方法。 这意味着,如果你在`String`中调用这些`NSString`的方法,将不用进行转换。
> 更多关于在 Foundation 和 Cocoa 中使用`String`的信息请查看 *[Using Swift with Cocoa and Objective-C (Swift 4)](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)*。 > 更多关于在 Foundation 和 Cocoa 中使用`String`的信息请查看 *[Using Swift with Cocoa and Objective-C (Swift 4)](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)*。
<a name="string_literals"></a> <a name="string_literals"></a>
@ -182,7 +182,7 @@ constantString += " and another Highlander"
// 这会报告一个编译错误 (compile-time error) - 常量字符串不可以被修改。 // 这会报告一个编译错误 (compile-time error) - 常量字符串不可以被修改。
``` ```
> 注意: > 注意:
在 Objective-C 和 Cocoa 中,您需要通过选择两个不同的类(`NSString``NSMutableString`)来指定字符串是否可以被修改。 在 Objective-C 和 Cocoa 中,您需要通过选择两个不同的类(`NSString``NSMutableString`)来指定字符串是否可以被修改。
<a name="strings_are_value_types"></a> <a name="strings_are_value_types"></a>
@ -259,7 +259,7 @@ welcome.append(exclamationMark)
// welcome 现在等于 "hello there!" // welcome 现在等于 "hello there!"
``` ```
> 注意: > 注意:
您不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。 您不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。
如果你需要使用多行字符串字面量来拼接字符串,并且你需要字符串每一行都以换行符结尾,包括最后一行: 如果你需要使用多行字符串字面量来拼接字符串,并且你需要字符串每一行都以换行符结尾,包括最后一行:
@ -310,7 +310,7 @@ let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
该表达式计算`Double(multiplier) * 2.5`的值并将结果 (`7.5`) 插入到字符串中。 该表达式计算`Double(multiplier) * 2.5`的值并将结果 (`7.5`) 插入到字符串中。
在这个例子中,表达式写为`\(Double(multiplier) * 2.5)`并包含在字符串字面量中。 在这个例子中,表达式写为`\(Double(multiplier) * 2.5)`并包含在字符串字面量中。
> 注意: > 注意:
> 插值字符串中写在括号中的表达式不能包含非转义反斜杠 (`\`),并且不能包含回车或换行符。不过,插值字符串可以包含其他字面量。 > 插值字符串中写在括号中的表达式不能包含非转义反斜杠 (`\`),并且不能包含回车或换行符。不过,插值字符串可以包含其他字面量。
<a name="unicode"></a> <a name="unicode"></a>
@ -337,7 +337,7 @@ Unicode 标量是对应字符或者修饰符的唯一的21位数字例如`U+0
### 可扩展的字形群集 ### 可扩展的字形群集
每一个 Swift 的`Character`类型代表一个*可扩展的字形群*。 每一个 Swift 的`Character`类型代表一个*可扩展的字形群*。
一个可扩展的字形群是一个或多个可生成人类可读的字符 Unicode 标量的有序排列。 一个可扩展的字形群是一个或多个可生成人类可读的字符 Unicode 标量的有序排列。
举个例子,字母`é`可以用单一的 Unicode 标量`é`(`LATIN SMALL LETTER E WITH ACUTE`, 或者`U+00E9`)来表示。然而一个标准的字母`e`(`LATIN SMALL LETTER E`或者`U+0065`) 加上一个急促重音(`COMBINING ACTUE ACCENT`)的标量(`U+0301`),这样一对标量就表示了同样的字母`é` 举个例子,字母`é`可以用单一的 Unicode 标量`é`(`LATIN SMALL LETTER E WITH ACUTE`, 或者`U+00E9`)来表示。然而一个标准的字母`e`(`LATIN SMALL LETTER E`或者`U+0065`) 加上一个急促重音(`COMBINING ACTUE ACCENT`)的标量(`U+0301`),这样一对标量就表示了同样的字母`é`
这个急促重音的标量形象的将`e`转换成了`é` 这个急促重音的标量形象的将`e`转换成了`é`
@ -400,7 +400,7 @@ print("the number of characters in \(word) is \(word.count)")
// 打印输出 "the number of characters in café is 4" // 打印输出 "the number of characters in café is 4"
``` ```
> 注意: > 注意:
> 可扩展的字符群集可以组成一个或者多个 Unicode 标量。这意味着不同的字符以及相同字符的不同表示方式可能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间数量。因此在没有获取字符串的可扩展的字符群的范围时候,就不能计算出字符串的字符数量。如果您正在处理一个长字符串,需要注意`count`属性必须遍历全部的 Unicode 标量,来确定字符串的字符数量。 > 可扩展的字符群集可以组成一个或者多个 Unicode 标量。这意味着不同的字符以及相同字符的不同表示方式可能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间数量。因此在没有获取字符串的可扩展的字符群的范围时候,就不能计算出字符串的字符数量。如果您正在处理一个长字符串,需要注意`count`属性必须遍历全部的 Unicode 标量,来确定字符串的字符数量。
> >
> 另外需要注意的是通过`count`属性返回的字符数量并不总是与包含相同字符的`NSString`的`length`属性相同。`NSString`的`length`属性是利用 UTF-16 表示的十六位代码单元数字,而不是 Unicode 可扩展的字符群集。 > 另外需要注意的是通过`count`属性返回的字符数量并不总是与包含相同字符的`NSString`的`length`属性相同。`NSString`的`length`属性是利用 UTF-16 表示的十六位代码单元数字,而不是 Unicode 可扩展的字符群集。
@ -452,7 +452,7 @@ for index in greeting.indices {
// 打印输出 "G u t e n T a g ! " // 打印输出 "G u t e n T a g ! "
``` ```
> 注意: > 注意:
> 您可以使用 `startIndex` 和 `endIndex` 属性或者 `index(before:)` 、`index(after:)` 和 `index(_:offsetBy:)` 方法在任意一个确认的并遵循 `Collection` 协议的类型里面,如上文所示是使用在 `String` 中,您也可以使用在 `Array`、`Dictionary` 和 `Set`中。 > 您可以使用 `startIndex` 和 `endIndex` 属性或者 `index(before:)` 、`index(after:)` 和 `index(_:offsetBy:)` 方法在任意一个确认的并遵循 `Collection` 协议的类型里面,如上文所示是使用在 `String` 中,您也可以使用在 `Array`、`Dictionary` 和 `Set`中。
<a name="inserting_and_removing"></a> <a name="inserting_and_removing"></a>
@ -556,7 +556,7 @@ if latinCapitalLetterA != cyrillicCapitalLetterA {
// 打印 "These two characters are not equivalent" // 打印 "These two characters are not equivalent"
``` ```
> 注意: > 注意:
> 在 Swift 中,字符串和字符并不区分地域(not locale-sensitive)。 > 在 Swift 中,字符串和字符并不区分地域(not locale-sensitive)。
<a name="prefix_and_suffix_equality"></a> <a name="prefix_and_suffix_equality"></a>
@ -611,7 +611,7 @@ print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
// 打印输出 "6 mansion scenes; 2 cell scenes" // 打印输出 "6 mansion scenes; 2 cell scenes"
``` ```
> 注意: > 注意:
> `hasPrefix(_:)`和`hasSuffix(_:)`方法都是在每个字符串中逐字符比较其可扩展的字符群集是否标准相等,详细描述在[字符串/字符相等](#string_and_character_equality)。 > `hasPrefix(_:)`和`hasSuffix(_:)`方法都是在每个字符串中逐字符比较其可扩展的字符群集是否标准相等,详细描述在[字符串/字符相等](#string_and_character_equality)。
<a name="unicode_representations_of_strings"></a> <a name="unicode_representations_of_strings"></a>

View File

@ -9,13 +9,13 @@
> 翻译+校对:[JackAlan](https://github.com/AlanMelody) > 翻译+校对:[JackAlan](https://github.com/AlanMelody)
> 2.1 > 2.1
> 校对:[shanks](http://codebuild.me) > 校对:[shanks](http://codebuild.me)
> 2.2 > 2.2
> 校对:[SketchK](https://github.com/SketchK) 2016-05-11 > 校对:[SketchK](https://github.com/SketchK) 2016-05-11
> >
> 3.0 > 3.0
> 校对:[shanks](http://codebuild.me) 2016-10-09 > 校对:[shanks](http://codebuild.me) 2016-10-09
> 3.0.1shanks2016-11-12 > 3.0.1shanks2016-11-12
本页包含内容: 本页包含内容:
@ -32,7 +32,7 @@ Swift 语言提供`Arrays`、`Sets`和`Dictionaries`三种基本的*集合类型
Swift 语言中的`Arrays``Sets``Dictionaries`中存储的数据值类型必须明确。这意味着我们不能把不正确的数据类型插入其中。同时这也说明我们完全可以对取回值的类型非常自信。 Swift 语言中的`Arrays``Sets``Dictionaries`中存储的数据值类型必须明确。这意味着我们不能把不正确的数据类型插入其中。同时这也说明我们完全可以对取回值的类型非常自信。
> 注意: > 注意:
Swift 的`Arrays``Sets``Dictionaries`类型被实现为*泛型集合*。更多关于泛型类型和集合,参见 [泛型](./23_Generics.html)章节。 Swift 的`Arrays``Sets``Dictionaries`类型被实现为*泛型集合*。更多关于泛型类型和集合,参见 [泛型](./23_Generics.html)章节。
<a name="mutability_of_collections"></a> <a name="mutability_of_collections"></a>
@ -40,7 +40,7 @@ Swift 的`Arrays`、`Sets`和`Dictionaries`类型被实现为*泛型集合*。
如果创建一个`Arrays``Sets``Dictionaries`并且把它分配成一个变量,这个集合将会是*可变的*。这意味着我们可以在创建之后添加更多或移除已存在的数据项,或者改变集合中的数据项。如果我们把`Arrays``Sets``Dictionaries`分配成常量,那么它就是*不可变的*,它的大小和内容都不能被改变。 如果创建一个`Arrays``Sets``Dictionaries`并且把它分配成一个变量,这个集合将会是*可变的*。这意味着我们可以在创建之后添加更多或移除已存在的数据项,或者改变集合中的数据项。如果我们把`Arrays``Sets``Dictionaries`分配成常量,那么它就是*不可变的*,它的大小和内容都不能被改变。
> 注意: > 注意:
在我们不需要改变集合的时候创建不可变集合是很好的实践。如此 Swift 编译器可以优化我们创建的集合。 在我们不需要改变集合的时候创建不可变集合是很好的实践。如此 Swift 编译器可以优化我们创建的集合。
<a name="arrays"></a> <a name="arrays"></a>
@ -118,7 +118,7 @@ var shoppingList: [String] = ["Eggs", "Milk"]
`shoppingList`变量被声明为“字符串值类型的数组“,记作`[String]`。 因为这个数组被规定只有`String`一种数据结构,所以只有`String`类型可以在其中被存取。 在这里,`shoppingList`数组由两个`String`值(`"Eggs"``"Milk"`)构造,并且由数组字面量定义。 `shoppingList`变量被声明为“字符串值类型的数组“,记作`[String]`。 因为这个数组被规定只有`String`一种数据结构,所以只有`String`类型可以在其中被存取。 在这里,`shoppingList`数组由两个`String`值(`"Eggs"``"Milk"`)构造,并且由数组字面量定义。
> 注意: > 注意:
`shoppingList`数组被声明为变量(`var`关键字创建)而不是常量(`let`创建)是因为以后可能会有更多的数据项被插入其中。 `shoppingList`数组被声明为变量(`var`关键字创建)而不是常量(`let`创建)是因为以后可能会有更多的数据项被插入其中。
在这个例子中,字面量仅仅包含两个`String`值。匹配了该数组的变量声明(只能包含`String`的数组),所以这个字面量的分配过程可以作为用两个初始项来构造`shoppingList`的一种方式。 在这个例子中,字面量仅仅包含两个`String`值。匹配了该数组的变量声明(只能包含`String`的数组),所以这个字面量的分配过程可以作为用两个初始项来构造`shoppingList`的一种方式。
@ -177,7 +177,7 @@ var firstItem = shoppingList[0]
// 第一项是 "Eggs" // 第一项是 "Eggs"
``` ```
> 注意: > 注意:
第一项在数组中的索引值是`0`而不是`1`。 Swift 中的数组索引总是从零开始。 第一项在数组中的索引值是`0`而不是`1`。 Swift 中的数组索引总是从零开始。
我们也可以用下标来改变某个已有索引值对应的数据值: 我们也可以用下标来改变某个已有索引值对应的数据值:
@ -194,7 +194,7 @@ shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList 现在有6项 // shoppingList 现在有6项
``` ```
> 注意: > 注意:
不可以用下标访问的形式去在数组尾部添加新项。 不可以用下标访问的形式去在数组尾部添加新项。
调用数组的`insert(_:at:)`方法来在某个具体索引值之前添加数据项: 调用数组的`insert(_:at:)`方法来在某个具体索引值之前添加数据项:
@ -215,7 +215,7 @@ let mapleSyrup = shoppingList.remove(at: 0)
// shoppingList 现在只有6项而且不包括 Maple Syrup // shoppingList 现在只有6项而且不包括 Maple Syrup
// mapleSyrup 常量的值等于被移除数据项的值 "Maple Syrup" // mapleSyrup 常量的值等于被移除数据项的值 "Maple Syrup"
``` ```
> 注意: > 注意:
如果我们试着对索引越界的数据进行检索或者设置新值的操作,会引发一个运行期错误。我们可以使用索引值和数组的`count`属性进行比较来在使用某个索引之前先检验是否有效。除了当`count`等于 0 时(说明这是个空数组),最大索引值一直是`count - 1`,因为数组都是零起索引。 如果我们试着对索引越界的数据进行检索或者设置新值的操作,会引发一个运行期错误。我们可以使用索引值和数组的`count`属性进行比较来在使用某个索引之前先检验是否有效。除了当`count`等于 0 时(说明这是个空数组),最大索引值一直是`count - 1`,因为数组都是零起索引。
数据项被移除后数组中的空出项会被自动填补,所以现在索引值为`0`的数据项的值再次等于`"Six eggs"` 数据项被移除后数组中的空出项会被自动填补,所以现在索引值为`0`的数据项的值再次等于`"Six eggs"`
@ -270,8 +270,8 @@ for (index, value) in shoppingList. enumerated() {
*集合(Set)*用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。 *集合(Set)*用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。
> 注意: > 注意:
> Swift的`Set`类型被桥接到`Foundation`中的`NSSet`类。 > Swift的`Set`类型被桥接到`Foundation`中的`NSSet`类。
> 关于使用`Foundation`和`Cocoa`中`Set`的知识,参见 [*Using Swift with Cocoa and Obejective-C(Swift 3.0.1)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中[使用 Cocoa 数据类型](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)部分。 > 关于使用`Foundation`和`Cocoa`中`Set`的知识,参见 [*Using Swift with Cocoa and Obejective-C(Swift 3.0.1)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中[使用 Cocoa 数据类型](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)部分。
<a name="hash_values_for_set_types"></a> <a name="hash_values_for_set_types"></a>
@ -281,8 +281,8 @@ for (index, value) in shoppingList. enumerated() {
Swift 的所有基本类型(比如`String`,`Int`,`Double``Bool`)默认都是可哈希化的,可以作为集合的值的类型或者字典的键的类型。没有关联值的枚举成员值(在[枚举](./08_Enumerations.html)有讲述)默认也是可哈希化的。 Swift 的所有基本类型(比如`String`,`Int`,`Double``Bool`)默认都是可哈希化的,可以作为集合的值的类型或者字典的键的类型。没有关联值的枚举成员值(在[枚举](./08_Enumerations.html)有讲述)默认也是可哈希化的。
> 注意: > 注意:
> 你可以使用你自定义的类型作为集合的值的类型或者是字典的键的类型,但你需要使你的自定义类型符合 Swift 标准库中的`Hashable`协议。符合`Hashable`协议的类型需要提供一个类型为`Int`的可读属性`hashValue`。由类型的`hashValue`属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。 > 你可以使用你自定义的类型作为集合的值的类型或者是字典的键的类型,但你需要使你的自定义类型符合 Swift 标准库中的`Hashable`协议。符合`Hashable`协议的类型需要提供一个类型为`Int`的可读属性`hashValue`。由类型的`hashValue`属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。
> 因为`Hashable`协议符合`Equatable`协议,所以遵循该协议的类型也必须提供一个"是否相等"运算符(`==`)的实现。这个`Equatable`协议要求任何符合`==`实现的实例间都是一种相等的关系。也就是说,对于`a,b,c`三个值来说,`==`的实现必须满足下面三种情况: > 因为`Hashable`协议符合`Equatable`协议,所以遵循该协议的类型也必须提供一个"是否相等"运算符(`==`)的实现。这个`Equatable`协议要求任何符合`==`实现的实例间都是一种相等的关系。也就是说,对于`a,b,c`三个值来说,`==`的实现必须满足下面三种情况:
@ -308,7 +308,7 @@ print("letters is of type Set<Character> with \(letters.count) items.")
// 打印 "letters is of type Set<Character> with 0 items." // 打印 "letters is of type Set<Character> with 0 items."
``` ```
> 注意: > 注意:
> 通过构造器,这里的`letters`变量的类型被推断为`Set<Character>`。 > 通过构造器,这里的`letters`变量的类型被推断为`Set<Character>`。
此外,如果上下文提供了类型信息,比如作为函数的参数或者已知类型的变量或常量,我们可以通过一个空的数组字面量创建一个空的`Set` 此外,如果上下文提供了类型信息,比如作为函数的参数或者已知类型的变量或常量,我们可以通过一个空的数组字面量创建一个空的`Set`
@ -334,7 +334,7 @@ var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
这个`favoriteGenres`变量被声明为“一个`String`值的集合”,写为`Set<String>`。由于这个特定的集合含有指定`String`类型的值,所以它只允许存储`String`类型值。这里的`favoriteGenres`变量有三个`String`类型的初始值(`"Rock"``"Classical"``"Hip hop"`),并以数组字面量的方式出现。 这个`favoriteGenres`变量被声明为“一个`String`值的集合”,写为`Set<String>`。由于这个特定的集合含有指定`String`类型的值,所以它只允许存储`String`类型值。这里的`favoriteGenres`变量有三个`String`类型的初始值(`"Rock"``"Classical"``"Hip hop"`),并以数组字面量的方式出现。
> 注意: > 注意:
> `favoriteGenres`被声明为一个变量(拥有`var`标示符)而不是一个常量(拥有`let`标示符),因为它里面的元素将会在下面的例子中被增加或者移除。 > `favoriteGenres`被声明为一个变量(拥有`var`标示符)而不是一个常量(拥有`let`标示符),因为它里面的元素将会在下面的例子中被增加或者移除。
一个`Set`类型不能从数组字面量中被单独推断出来,因此`Set`类型必须显式声明。然而,由于 Swift 的类型推断功能,如果你想使用一个数组字面量构造一个`Set`并且该数组字面量中的所有元素类型相同,那么你无须写出`Set`的具体类型。`favoriteGenres`的构造形式可以采用简化的方式代替: 一个`Set`类型不能从数组字面量中被单独推断出来,因此`Set`类型必须显式声明。然而,由于 Swift 的类型推断功能,如果你想使用一个数组字面量构造一个`Set`并且该数组字面量中的所有元素类型相同,那么你无须写出`Set`的具体类型。`favoriteGenres`的构造形式可以采用简化的方式代替:
@ -487,8 +487,8 @@ farmAnimals.isDisjoint(with: cityAnimals)
*字典*是一种存储多个相同类型的值的容器。每个值value都关联唯一的键key键作为字典中的这个值数据的标识符。和数组中的数据项不同字典中的数据项并没有具体顺序。我们在需要通过标识符访问数据的时候使用字典这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。 *字典*是一种存储多个相同类型的值的容器。每个值value都关联唯一的键key键作为字典中的这个值数据的标识符。和数组中的数据项不同字典中的数据项并没有具体顺序。我们在需要通过标识符访问数据的时候使用字典这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。
> 注意: > 注意:
> Swift 的`Dictionary`类型被桥接到`Foundation`的`NSDictionary`类。 > Swift 的`Dictionary`类型被桥接到`Foundation`的`NSDictionary`类。
> 更多关于在`Foundation`和`Cocoa`中使用`Dictionary`类型的信息,参见 [*Using Swift with Cocoa and Obejective-C(Swift 3.0.1)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中[使用 Cocoa 数据类型](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)部分。 > 更多关于在`Foundation`和`Cocoa`中使用`Dictionary`类型的信息,参见 [*Using Swift with Cocoa and Obejective-C(Swift 3.0.1)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中[使用 Cocoa 数据类型](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)部分。
<a name="dictionary_type_shorthand_syntax"></a> <a name="dictionary_type_shorthand_syntax"></a>
@ -496,7 +496,7 @@ farmAnimals.isDisjoint(with: cityAnimals)
Swift 的字典使用`Dictionary<Key, Value>`定义,其中`Key`是字典中键的数据类型,`Value`是字典中对应于这些键所存储值的数据类型。 Swift 的字典使用`Dictionary<Key, Value>`定义,其中`Key`是字典中键的数据类型,`Value`是字典中对应于这些键所存储值的数据类型。
> 注意: > 注意:
> 一个字典的`Key`类型必须遵循`Hashable`协议,就像`Set`的值类型。 > 一个字典的`Key`类型必须遵循`Hashable`协议,就像`Set`的值类型。
我们也可以用`[Key: Value]`这样简化的形式去创建一个字典类型。虽然这两种形式功能上相同,但是后者是首选,并且这本指导书涉及到字典类型时通篇采用后者。 我们也可以用`[Key: Value]`这样简化的形式去创建一个字典类型。虽然这两种形式功能上相同,但是后者是首选,并且这本指导书涉及到字典类型时通篇采用后者。
@ -541,7 +541,7 @@ var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
`airports`字典被声明为一种`[String: String]`类型,这意味着这个字典的键和值都是`String`类型。 `airports`字典被声明为一种`[String: String]`类型,这意味着这个字典的键和值都是`String`类型。
> 注意: > 注意:
> `airports`字典被声明为变量(用`var`关键字)而不是常量(`let`关键字)因为后来更多的机场信息会被添加到这个示例字典中。 > `airports`字典被声明为变量(用`var`关键字)而不是常量(`let`关键字)因为后来更多的机场信息会被添加到这个示例字典中。
`airports`字典使用字典字面量初始化,包含两个键值对。第一对的键是`YYZ`,值是`Toronto Pearson`。第二对的键是`DUB`,值是`Dublin` `airports`字典使用字典字面量初始化,包含两个键值对。第一对的键是`YYZ`,值是`Toronto Pearson`。第二对的键是`DUB`,值是`Dublin`

View File

@ -17,11 +17,11 @@
> 校对:[SketchK](https://github.com/SketchK) > 校对:[SketchK](https://github.com/SketchK)
> 3.0 > 3.0
> 翻译:[Realank](https://github.com/realank) 2016-09-13 > 翻译:[Realank](https://github.com/realank) 2016-09-13
> 3.0.1shanks2016-11-12 > 3.0.1shanks2016-11-12
> 3.1 > 3.1
> 翻译:[qhd](https://github.com/qhd) 2017-04-17 > 翻译:[qhd](https://github.com/qhd) 2017-04-17
> 4.0 > 4.0
> 翻译:[kemchenj](https://kemchenj.github.io/) 2017-09-21 > 翻译:[kemchenj](https://kemchenj.github.io/) 2017-09-21
@ -46,7 +46,7 @@ Swift 的`switch`语句比 C 语言中更加强大。case 还可以匹配很多
你可以使用 `for-in` 循环来遍历一个集合中的所有元素,例如数组中的元素、范围内的数字或者字符串中的字符。 你可以使用 `for-in` 循环来遍历一个集合中的所有元素,例如数组中的元素、范围内的数字或者字符串中的字符。
以下例子使用 `for-in` 遍历一个数组所有元素: 以下例子使用 `for-in` 遍历一个数组所有元素:
```swift ```swift
let names = ["Anna", "Alex", "Brian", "Jack"] let names = ["Anna", "Alex", "Brian", "Jack"]
@ -59,7 +59,7 @@ for name in names {
// Hello, Jack! // Hello, Jack!
``` ```
你也可以通过遍历一个字典来访问它的键值对。遍历字典时,字典的每项元素会以 `(key, value)` 元组的形式返回,你可以在 `for-in` 循环中使用显式的常量名称来解读 `(key, value)` 元组。下面的例子中,字典的键声明会为 `animalName` 常量,字典的值会声明为 `legCount` 常量: 你也可以通过遍历一个字典来访问它的键值对。遍历字典时,字典的每项元素会以 `(key, value)` 元组的形式返回,你可以在 `for-in` 循环中使用显式的常量名称来解读 `(key, value)` 元组。下面的例子中,字典的键声明会为 `animalName` 常量,字典的值会声明为 `legCount` 常量:
```swift ```swift
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
@ -71,9 +71,9 @@ for (animalName, legCount) in numberOfLegs {
// cats have 4 legs // cats have 4 legs
``` ```
字典的内容理论上是无序的,遍历元素时的顺序是无法确定的。将元素插入字典的顺序并不会决定它们被遍历的顺序。关于数组和字典的细节,参见[集合类型](./04_Collection_Types.html)。 字典的内容理论上是无序的,遍历元素时的顺序是无法确定的。将元素插入字典的顺序并不会决定它们被遍历的顺序。关于数组和字典的细节,参见[集合类型](./04_Collection_Types.html)。
`for-in` 循环还可以使用数字范围。下面的例子用来输出乘法表的一部分内容: `for-in` 循环还可以使用数字范围。下面的例子用来输出乘法表的一部分内容:
```swift ```swift
for index in 1...5 { for index in 1...5 {
@ -86,11 +86,11 @@ for index in 1...5 {
// 5 times 5 is 25 // 5 times 5 is 25
``` ```
例子中用来进行遍历的元素是使用闭区间操作符(`...`)表示的从 `1``5` 的数字区间。`index` 被赋值为闭区间中的第一个数字(`1`),然后循环中的语句被执行一次。在本例中,这个循环只包含一个语句,用来输出当前 `index` 值所对应的乘 5 乘法表的结果。该语句执行后,`index` 的值被更新为闭区间中的第二个数字(`2`),之后 `print(_:separator:terminator:)` 函数会再执行一次。整个过程会进行到闭区间结尾为止。 例子中用来进行遍历的元素是使用闭区间操作符(`...`)表示的从 `1``5` 的数字区间。`index` 被赋值为闭区间中的第一个数字(`1`),然后循环中的语句被执行一次。在本例中,这个循环只包含一个语句,用来输出当前 `index` 值所对应的乘 5 乘法表的结果。该语句执行后,`index` 的值被更新为闭区间中的第二个数字(`2`),之后 `print(_:separator:terminator:)` 函数会再执行一次。整个过程会进行到闭区间结尾为止。
上面的例子中,`index` 是一个每次循环遍历开始时被自动赋值的常量。这种情况下,`index` 在使用前不需要声明,只需要将它包含在循环的声明中,就可以对其进行隐式声明,而无需使用 `let` 关键字声明。 上面的例子中,`index` 是一个每次循环遍历开始时被自动赋值的常量。这种情况下,`index` 在使用前不需要声明,只需要将它包含在循环的声明中,就可以对其进行隐式声明,而无需使用 `let` 关键字声明。
如果你不需要区间序列内每一项的值,你可以使用下划线(`_`)替代变量名来忽略这个值: 如果你不需要区间序列内每一项的值,你可以使用下划线(`_`)替代变量名来忽略这个值:
```swift ```swift
let base = 3 let base = 3
@ -103,9 +103,9 @@ print("\(base) to the power of \(power) is \(answer)")
// 输出 "3 to the power of 10 is 59049" // 输出 "3 to the power of 10 is 59049"
``` ```
这个例子计算 base 这个数的 power 次幂(本例中,是 `3``10` 次幂),从 `1` `3``0` 次幂)开始做 `3` 的乘法, 进行 `10` 次,使用 `1``10` 的闭区间循环。这个计算并不需要知道每一次循环中计数器具体的值,只需要执行了正确的循环次数即可。下划线符号 `_` (替代循环中的变量)能够忽略当前值,并且不提供循环遍历时对值的访问。 这个例子计算 base 这个数的 power 次幂(本例中,是 `3``10` 次幂),从 `1` `3``0` 次幂)开始做 `3` 的乘法, 进行 `10` 次,使用 `1``10` 的闭区间循环。这个计算并不需要知道每一次循环中计数器具体的值,只需要执行了正确的循环次数即可。下划线符号 `_` (替代循环中的变量)能够忽略当前值,并且不提供循环遍历时对值的访问。
在某些情况下,你可能不想使用闭区间,包括两个端点。想象一下,你在一个手表上绘制分钟的刻度线。总共 `60` 个刻度,从 `0` 分开始。使用半开区间运算符(`..<`)来表示一个左闭右开的区间。有关区间的更多信息,请参阅[区间运算符](./02_Basic_Operators.html#range_operators)。 在某些情况下,你可能不想使用闭区间,包括两个端点。想象一下,你在一个手表上绘制分钟的刻度线。总共 `60` 个刻度,从 `0` 分开始。使用半开区间运算符(`..<`)来表示一个左闭右开的区间。有关区间的更多信息,请参阅[区间运算符](./02_Basic_Operators.html#range_operators)。
``` ```
let minutes = 60 let minutes = 60
@ -114,7 +114,7 @@ for tickMark in 0..<minutes {
} }
``` ```
一些用户可能在其UI中可能需要较少的刻度。他们可以每5分钟作为一个刻度。使用 `stride(from:to:by:)` 函数跳过不需要的标记。 一些用户可能在其UI中可能需要较少的刻度。他们可以每5分钟作为一个刻度。使用 `stride(from:to:by:)` 函数跳过不需要的标记。
``` ```
let minuteInterval = 5 let minuteInterval = 5
@ -123,7 +123,7 @@ for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
} }
``` ```
可以在闭区间使用 `stride(from:through:by:)` 起到同样作用: 可以在闭区间使用 `stride(from:through:by:)` 起到同样作用:
``` ```
let hours = 12 let hours = 12
@ -149,7 +149,7 @@ for tickMark in stride(from: 3, through: hours, by: hourInterval) {
下面是 `while` 循环的一般格式: 下面是 `while` 循环的一般格式:
``` ```
while condition { while condition {
statements statements
} }
``` ```
@ -204,7 +204,7 @@ print("Game over!")
掷完骰子后,玩家向前移动`diceRoll`个方格,如果玩家移动超过了第 25 个方格,这个时候游戏将会结束,为了应对这种情况,代码会首先判断`square`的值是否小于`board``count`属性,只有小于才会在`board[square]`上增加`square`,来向前或向后移动(遇到了梯子或者蛇)。 掷完骰子后,玩家向前移动`diceRoll`个方格,如果玩家移动超过了第 25 个方格,这个时候游戏将会结束,为了应对这种情况,代码会首先判断`square`的值是否小于`board``count`属性,只有小于才会在`board[square]`上增加`square`,来向前或向后移动(遇到了梯子或者蛇)。
> 注意: > 注意:
> 如果没有这个检测(`square < board.count``board[square]`可能会越界访问`board`数组,导致错误。 > 如果没有这个检测(`square < board.count``board[square]`可能会越界访问`board`数组,导致错误。
当本轮`while`循环运行完毕,会再检测循环条件是否需要再运行一次循环。如果玩家移动到或者超过第 25 个方格,循环条件结果为`false`,此时游戏结束。 当本轮`while`循环运行完毕,会再检测循环条件是否需要再运行一次循环。如果玩家移动到或者超过第 25 个方格,循环条件结果为`false`,此时游戏结束。
@ -216,7 +216,7 @@ print("Game over!")
`while`循环的另外一种形式是`repeat-while`,它和`while`的区别是在判断循环条件之前,先执行一次循环的代码块。然后重复循环直到条件为`false` `while`循环的另外一种形式是`repeat-while`,它和`while`的区别是在判断循环条件之前,先执行一次循环的代码块。然后重复循环直到条件为`false`
> 注意: > 注意:
> Swift语言的`repeat-while`循环和其他语言中的`do-while`循环是类似的。 > Swift语言的`repeat-while`循环和其他语言中的`do-while`循环是类似的。
下面是 `repeat-while`循环的一般格式: 下面是 `repeat-while`循环的一般格式:
@ -743,7 +743,7 @@ print("Game over!")
- 如果骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子。`continue gameLoop`语句结束本次`while`循环,开始下一次循环。 - 如果骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子。`continue gameLoop`语句结束本次`while`循环,开始下一次循环。
- 在剩余的所有情况中,骰子数产生的都是合法的移动。玩家向前移动 `diceRoll` 个方格,然后游戏逻辑再处理玩家当前是否处于蛇头或者梯子的底部。接着本次循环结束,控制跳转到`while`循环体的条件判断语句处,再决定是否需要继续执行下次循环。 - 在剩余的所有情况中,骰子数产生的都是合法的移动。玩家向前移动 `diceRoll` 个方格,然后游戏逻辑再处理玩家当前是否处于蛇头或者梯子的底部。接着本次循环结束,控制跳转到`while`循环体的条件判断语句处,再决定是否需要继续执行下次循环。
>注意: >注意:
如果上述的`break`语句没有使用`gameLoop`标签,那么它将会中断`switch`语句而不是`while`循环。使用`gameLoop`标签清晰的表明了`break`想要中断的是哪个代码块。 如果上述的`break`语句没有使用`gameLoop`标签,那么它将会中断`switch`语句而不是`while`循环。使用`gameLoop`标签清晰的表明了`break`想要中断的是哪个代码块。
同时请注意,当调用`continue gameLoop`去跳转到下一次循环迭代时,这里使用`gameLoop`标签并不是严格必须的。因为在这个游戏中,只有一个循环体,所以`continue`语句会影响到哪个循环体是没有歧义的。然而,`continue`语句使用`gameLoop`标签也是没有危害的。这样做符合标签的使用规则,同时参照旁边的`break gameLoop`,能够使游戏的逻辑更加清晰和易于理解。 同时请注意,当调用`continue gameLoop`去跳转到下一次循环迭代时,这里使用`gameLoop`标签并不是严格必须的。因为在这个游戏中,只有一个循环体,所以`continue`语句会影响到哪个循环体是没有歧义的。然而,`continue`语句使用`gameLoop`标签也是没有危害的。这样做符合标签的使用规则,同时参照旁边的`break gameLoop`,能够使游戏的逻辑更加清晰和易于理解。

View File

@ -30,7 +30,7 @@
- [函数类型](#Function_Types) - [函数类型](#Function_Types)
- [嵌套函数](#Nested_Functions) - [嵌套函数](#Nested_Functions)
*函数*是一段完成特定任务的独立代码片段。你可以通过给函数命名来标识某个函数的功能,这个名字可以被用来在需要的时候"调用"这个函数来完成它的任务。 *函数*是一段完成特定任务的独立代码片段。你可以通过给函数命名来标识某个函数的功能,这个名字可以被用来在需要的时候"调用"这个函数来完成它的任务。
Swift 统一的函数语法非常的灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以既当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值将被修改。 Swift 统一的函数语法非常的灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以既当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值将被修改。
@ -65,7 +65,7 @@ print(greet(person: "Brian"))
调用 `greet(person:)` 函数时,在圆括号中传给它一个 `String` 类型的实参,例如 `greet(person: "Anna")`。正如上面所示,因为这个函数返回一个 `String` 类型的值,所以`greet ` 可以被包含在 `print(_:separator:terminator:)` 的调用中,用来输出这个函数的返回值。 调用 `greet(person:)` 函数时,在圆括号中传给它一个 `String` 类型的实参,例如 `greet(person: "Anna")`。正如上面所示,因为这个函数返回一个 `String` 类型的值,所以`greet ` 可以被包含在 `print(_:separator:terminator:)` 的调用中,用来输出这个函数的返回值。
>注意 >注意
`print(_:separator:terminator:)` 函数的第一个参数并没有设置一个标签,而其他的参数因为已经有了默认值,因此是可选的。关于这些函数语法上的变化详见下方关于 函数参数标签和参数名 以及 默认参数值。 `print(_:separator:terminator:)` 函数的第一个参数并没有设置一个标签,而其他的参数因为已经有了默认值,因此是可选的。关于这些函数语法上的变化详见下方关于 函数参数标签和参数名 以及 默认参数值。
`greet(person:)` 的函数体中,先定义了一个新的名为 `greeting``String` 常量,同时,把对 `personName` 的问候消息赋值给了 `greeting` 。然后用 `return` 关键字把这个问候返回出去。一旦 `return greeting` 被调用,该函数结束它的执行并返回 `greeting` 的当前值。 `greet(person:)` 的函数体中,先定义了一个新的名为 `greeting``String` 常量,同时,把对 `personName` 的问候消息赋值给了 `greeting` 。然后用 `return` 关键字把这个问候返回出去。一旦 `return greeting` 被调用,该函数结束它的执行并返回 `greeting` 的当前值。
@ -138,7 +138,7 @@ greet(person: "Dave")
因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。 因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。
>注意 >注意
严格上来说,虽然没有返回值被定义,`greet(person:)` 函数依然返回了值。没有定义返回类型的函数会返回一个特殊的`Void`值。它其实是一个空的元组tuple没有任何元素可以写成()。 严格上来说,虽然没有返回值被定义,`greet(person:)` 函数依然返回了值。没有定义返回类型的函数会返回一个特殊的`Void`值。它其实是一个空的元组tuple没有任何元素可以写成()。
被调用时,一个函数的返回值可以被忽略: 被调用时,一个函数的返回值可以被忽略:
@ -159,7 +159,7 @@ printWithoutCounting(string: "hello, world")
第一个函数 `printAndCount(string:)`,输出一个字符串并返回 `Int` 类型的字符数。第二个函数 `printWithoutCounting(string:)`调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,消息依然会由第一个函数输出,但是返回值不会被用到。 第一个函数 `printAndCount(string:)`,输出一个字符串并返回 `Int` 类型的字符数。第二个函数 `printWithoutCounting(string:)`调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,消息依然会由第一个函数输出,但是返回值不会被用到。
>注意: >注意:
返回值可以被忽略但定义了有返回值的函数必须返回一个值如果在函数定义底部没有返回任何值将导致编译时错误compile-time error 返回值可以被忽略但定义了有返回值的函数必须返回一个值如果在函数定义底部没有返回任何值将导致编译时错误compile-time error
<a name="functions_with_multiple_return_values"></a> <a name="functions_with_multiple_return_values"></a>
@ -324,7 +324,7 @@ arithmeticMean(3, 8.25, 18.75)
// 返回 10.0, 是这 3 个数的平均数。 // 返回 10.0, 是这 3 个数的平均数。
``` ```
>注意: >注意:
一个函数最多只能拥有一个可变参数。 一个函数最多只能拥有一个可变参数。
<a name="in_out_parameters"></a> <a name="in_out_parameters"></a>
@ -363,7 +363,7 @@ print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
从上面这个例子中,我们可以看到 `someInt``anotherInt` 的原始值在 `swapTwoInts(_:_:)` 函数中被修改,尽管它们的定义在函数体外。 从上面这个例子中,我们可以看到 `someInt``anotherInt` 的原始值在 `swapTwoInts(_:_:)` 函数中被修改,尽管它们的定义在函数体外。
>注意: >注意:
输入输出参数和返回值是不一样的。上面的 `swapTwoInts` 函数并没有定义任何返回值,但仍然修改了 `someInt``anotherInt` 的值。输入输出参数是函数对函数体外产生影响的另一种方式。 输入输出参数和返回值是不一样的。上面的 `swapTwoInts` 函数并没有定义任何返回值,但仍然修改了 `someInt``anotherInt` 的值。输入输出参数是函数对函数体外产生影响的另一种方式。
<a name="Function_Types"></a> <a name="Function_Types"></a>

View File

@ -16,7 +16,7 @@
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-12 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-12
> >
> 3.0 > 3.0
> 翻译:[Lanford](https://github.com/LanfordCai) 2016-09-19 > 翻译:[Lanford](https://github.com/LanfordCai) 2016-09-19
> 3.0.1shanks2016-11-12 > 3.0.1shanks2016-11-12
> 4.0 > 4.0
@ -239,7 +239,7 @@ let strings = numbers.map {
闭包表达式在每次被调用的时候创建了一个叫做 `output` 的字符串并返回。其使用求余运算符(`number % 10`)计算最后一位数字并利用 `digitNames` 字典获取所映射的字符串。这个闭包能够用于创建任意正整数的字符串表示。 闭包表达式在每次被调用的时候创建了一个叫做 `output` 的字符串并返回。其使用求余运算符(`number % 10`)计算最后一位数字并利用 `digitNames` 字典获取所映射的字符串。这个闭包能够用于创建任意正整数的字符串表示。
> 注意: > 注意:
> 字典 `digitNames` 下标后跟着一个叹号(`!`因为字典下标返回一个可选值optional value表明该键不存在时会查找失败。在上例中由于可以确定 `number % 10` 总是 `digitNames` 字典的有效下标,因此叹号可以用于强制解包 (force-unwrap) 存储在下标的可选类型的返回值中的`String`类型的值。 > 字典 `digitNames` 下标后跟着一个叹号(`!`因为字典下标返回一个可选值optional value表明该键不存在时会查找失败。在上例中由于可以确定 `number % 10` 总是 `digitNames` 字典的有效下标,因此叹号可以用于强制解包 (force-unwrap) 存储在下标的可选类型的返回值中的`String`类型的值。
`digitNames` 字典中获取的字符串被添加到 `output` 的*前部*,逆序建立了一个字符串版本的数字。(在表达式 `number % 10` 中,如果 `number``16`,则返回 `6``58` 返回 `8``510` 返回 `0`。) `digitNames` 字典中获取的字符串被添加到 `output` 的*前部*,逆序建立了一个字符串版本的数字。(在表达式 `number % 10` 中,如果 `number``16`,则返回 `6``58` 返回 `8``510` 返回 `0`。)
@ -323,7 +323,7 @@ incrementByTen()
// 返回的值为40 // 返回的值为40
``` ```
> 注意: > 注意:
> 如果你将闭包赋值给一个类实例的属性并且该闭包通过访问该实例或其成员而捕获了该实例你将在闭包和该实例间创建一个循环强引用。Swift 使用捕获列表来打破这种循环强引用。更多信息,请参考[闭包引起的循环强引用](./16_Automatic_Reference_Counting.html#strong_reference_cycles_for_closures)。 > 如果你将闭包赋值给一个类实例的属性并且该闭包通过访问该实例或其成员而捕获了该实例你将在闭包和该实例间创建一个循环强引用。Swift 使用捕获列表来打破这种循环强引用。更多信息,请参考[闭包引起的循环强引用](./16_Automatic_Reference_Counting.html#strong_reference_cycles_for_closures)。
<a name="closures_are_reference_types"></a> <a name="closures_are_reference_types"></a>
@ -344,7 +344,7 @@ alsoIncrementByTen()
<a name="escaping_closures"></a> <a name="escaping_closures"></a>
## 逃逸闭包 ## 逃逸闭包
当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中*逃逸*。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 `@escaping`,用来指明这个闭包是允许“逃逸”出这个函数的。 当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中*逃逸*。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 `@escaping`,用来指明这个闭包是允许“逃逸”出这个函数的。
一种能使闭包“逃逸”出函数的方法是,将这个闭包保存在一个函数外部定义的变量中。举个例子,很多启动异步操作的函数接受一个闭包参数作为 completion handler。这类函数会在异步操作开始之后立刻返回但是闭包直到异步操作结束后才会被调用。在这种情况下闭包需要“逃逸”出函数因为闭包需要在函数返回之后被调用。例如 一种能使闭包“逃逸”出函数的方法是,将这个闭包保存在一个函数外部定义的变量中。举个例子,很多启动异步操作的函数接受一个闭包参数作为 completion handler。这类函数会在异步操作开始之后立刻返回但是闭包直到异步操作结束后才会被调用。在这种情况下闭包需要“逃逸”出函数因为闭包需要在函数返回之后被调用。例如

View File

@ -16,7 +16,7 @@
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-13 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-13
> 3.0 > 3.0
> 翻译+校对:[shanks](https://codebuild.me) 2016-09-24 > 翻译+校对:[shanks](https://codebuild.me) 2016-09-24
> 3.0.1shanks2016-11-12 > 3.0.1shanks2016-11-12
> 4.0 > 4.0
@ -64,7 +64,7 @@ enum CompassPoint {
枚举中定义的值(如 `north ``south``east``west`)是这个枚举的*成员值*(或*成员*)。你可以使用`case`关键字来定义一个新的枚举成员值。 枚举中定义的值(如 `north ``south``east``west`)是这个枚举的*成员值*(或*成员*)。你可以使用`case`关键字来定义一个新的枚举成员值。
> 注意 > 注意
> 与 C 和 Objective-C 不同Swift 的枚举成员在被创建时不会被赋予一个默认的整型值。在上面的`CompassPoint`例子中,`north``south``east`和`west`不会被隐式地赋值为`0``1``2`和`3`。相反,这些枚举成员本身就是完备的值,这些值的类型是已经明确定义好的`CompassPoint`类型。 > 与 C 和 Objective-C 不同Swift 的枚举成员在被创建时不会被赋予一个默认的整型值。在上面的`CompassPoint`例子中,`north``south``east`和`west`不会被隐式地赋值为`0``1``2`和`3`。相反,这些枚举成员本身就是完备的值,这些值的类型是已经明确定义好的`CompassPoint`类型。
多个成员值可以出现在同一行上,用逗号隔开: 多个成员值可以出现在同一行上,用逗号隔开:
@ -221,7 +221,7 @@ enum ASCIIControlCharacter: Character {
原始值可以是字符串,字符,或者任意整型值或浮点型值。每个原始值在枚举声明中必须是唯一的。 原始值可以是字符串,字符,或者任意整型值或浮点型值。每个原始值在枚举声明中必须是唯一的。
> 注意 > 注意
> 原始值和关联值是不同的。原始值是在定义枚举时被预先填充的值,像上述三个 ASCII 码。对于一个特定的枚举成员,它的原始值始终不变。关联值是创建一个基于枚举成员的常量或变量时才设置的值,枚举成员的关联值可以变化。 > 原始值和关联值是不同的。原始值是在定义枚举时被预先填充的值,像上述三个 ASCII 码。对于一个特定的枚举成员,它的原始值始终不变。关联值是创建一个基于枚举成员的常量或变量时才设置的值,枚举成员的关联值可以变化。
<a name="implicitly_assigned_raw_values"></a> <a name="implicitly_assigned_raw_values"></a>
@ -277,7 +277,7 @@ let possiblePlanet = Planet(rawValue: 7)
然而,并非所有`Int`值都可以找到一个匹配的行星。因此,原始值构造器总是返回一个*可选*的枚举成员。在上面的例子中,`possiblePlanet``Planet?`类型,或者说“可选的`Planet`”。 然而,并非所有`Int`值都可以找到一个匹配的行星。因此,原始值构造器总是返回一个*可选*的枚举成员。在上面的例子中,`possiblePlanet``Planet?`类型,或者说“可选的`Planet`”。
> 注意 > 注意
> 原始值构造器是一个可失败构造器,因为并不是每一个原始值都有与之对应的枚举成员。更多信息请参见[可失败构造器](../chapter3/05_Declarations.html#failable_initializers) > 原始值构造器是一个可失败构造器,因为并不是每一个原始值都有与之对应的枚举成员。更多信息请参见[可失败构造器](../chapter3/05_Declarations.html#failable_initializers)
如果你试图寻找一个位置为`11`的行星,通过原始值构造器返回的可选`Planet`值将是`nil` 如果你试图寻找一个位置为`11`的行星,通过原始值构造器返回的可选`Planet`值将是`nil`
@ -302,7 +302,7 @@ if let somePlanet = Planet(rawValue: positionToFind) {
<a name="recursive_enumerations"></a> <a name="recursive_enumerations"></a>
## 递归枚举 ## 递归枚举
*递归枚举*是一种枚举类型,它有一个或多个枚举成员使用该枚举类型的实例作为关联值。使用递归枚举时,编译器会插入一个间接层。你可以在枚举成员前加上`indirect`来表示该成员可递归。 *递归枚举*是一种枚举类型,它有一个或多个枚举成员使用该枚举类型的实例作为关联值。使用递归枚举时,编译器会插入一个间接层。你可以在枚举成员前加上`indirect`来表示该成员可递归。
例如,下面的例子中,枚举类型存储了简单的算术表达式: 例如,下面的例子中,枚举类型存储了简单的算术表达式:

View File

@ -30,7 +30,7 @@
与其他编程语言所不同的是Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口。 与其他编程语言所不同的是Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口。
> 注意 > 注意
> 通常一个*类*的实例被称为*对象*。然而在 Swift 中,类和结构体的关系要比在其他语言中更加的密切,本章中所讨论的大部分功能都可以用在类和结构体上。因此,我们会主要使用*实例*。 > 通常一个*类*的实例被称为*对象*。然而在 Swift 中,类和结构体的关系要比在其他语言中更加的密切,本章中所讨论的大部分功能都可以用在类和结构体上。因此,我们会主要使用*实例*。
<a name="comparing_classes_and_structures"></a> <a name="comparing_classes_and_structures"></a>
@ -56,7 +56,7 @@ Swift 中类和结构体有很多共同点。共同处在于:
更多信息请参见[继承](./13_Inheritance.html)[类型转换](./19_Type_Casting.html)[析构过程](./15_Deinitialization.html),和[自动引用计数](./16_Automatic_Reference_Counting.html)。 更多信息请参见[继承](./13_Inheritance.html)[类型转换](./19_Type_Casting.html)[析构过程](./15_Deinitialization.html),和[自动引用计数](./16_Automatic_Reference_Counting.html)。
> 注意 > 注意
> 结构体总是通过被复制的方式在代码中传递,不使用引用计数。 > 结构体总是通过被复制的方式在代码中传递,不使用引用计数。
<a name="definition_syntax"></a> <a name="definition_syntax"></a>
@ -73,7 +73,7 @@ struct SomeStructure {
} }
``` ```
> 注意 > 注意
> 在你每次定义一个新类或者结构体的时候,实际上你是定义了一个新的 Swift 类型。因此请使用`UpperCamelCase`这种方式来命名(如`SomeClass`和`SomeStructure`等),以便符合标准 Swift 类型的大写命名风格(如`String``Int`和`Bool`)。相反的,请使用`lowerCamelCase`这种方式为属性和方法命名(如`framerate`和`incrementCount`),以便和类型名区分。 > 在你每次定义一个新类或者结构体的时候,实际上你是定义了一个新的 Swift 类型。因此请使用`UpperCamelCase`这种方式来命名(如`SomeClass`和`SomeStructure`等),以便符合标准 Swift 类型的大写命名风格(如`String``Int`和`Bool`)。相反的,请使用`lowerCamelCase`这种方式为属性和方法命名(如`framerate`和`incrementCount`),以便和类型名区分。
以下是定义结构体和定义类的示例: 以下是定义结构体和定义类的示例:
@ -136,7 +136,7 @@ print("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// 打印 "The width of someVideoMode is now 1280" // 打印 "The width of someVideoMode is now 1280"
``` ```
> 注意 > 注意
> 与 Objective-C 语言不同的是Swift 允许直接设置结构体属性的子属性。上面的最后一个例子,就是直接设置了`someVideoMode`中`resolution`属性的`width`这个子属性,以上操作并不需要重新为整个`resolution`属性设置新值。 > 与 Objective-C 语言不同的是Swift 允许直接设置结构体属性的子属性。上面的最后一个例子,就是直接设置了`someVideoMode`中`resolution`属性的`width`这个子属性,以上操作并不需要重新为整个`resolution`属性设置新值。
<a name="memberwise_initializers_for_structure_types"></a> <a name="memberwise_initializers_for_structure_types"></a>
@ -304,5 +304,5 @@ Swift 中,许多基本类型,诸如`String``Array`和`Dictionary`类型
Objective-C 中`NSString``NSArray``NSDictionary`类型均以类的形式实现,而并非结构体。它们在被赋值或者被传入函数或方法时,不会发生值拷贝,而是传递现有实例的引用。 Objective-C 中`NSString``NSArray``NSDictionary`类型均以类的形式实现,而并非结构体。它们在被赋值或者被传入函数或方法时,不会发生值拷贝,而是传递现有实例的引用。
> 注意 > 注意
> 以上是对字符串、数组、字典的“拷贝”行为的描述。在你的代码中拷贝行为看起来似乎总会发生。然而Swift 在幕后只在绝对必要时才执行实际的拷贝。Swift 管理所有的值拷贝以确保性能最优化,所以你没必要去回避赋值来保证性能最优化。 > 以上是对字符串、数组、字典的“拷贝”行为的描述。在你的代码中拷贝行为看起来似乎总会发生。然而Swift 在幕后只在绝对必要时才执行实际的拷贝。Swift 管理所有的值拷贝以确保性能最优化,所以你没必要去回避赋值来保证性能最优化。

View File

@ -79,8 +79,8 @@ rangeOfFourItems.firstValue = 6
*延迟存储属*性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用 `lazy` 来标示一个延迟存储属性。 *延迟存储属*性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用 `lazy` 来标示一个延迟存储属性。
> 注意 > 注意
> 必须将延迟存储属性声明成变量(使用 `var` 关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。 > 必须将延迟存储属性声明成变量(使用 `var` 关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
延迟属性很有用,当属性的值依赖于在实例的构造过程结束后才会知道影响值的外部因素时,或者当获得属性的初始值需要复杂或大量计算时,可以只在需要的时候计算它。 延迟属性很有用,当属性的值依赖于在实例的构造过程结束后才会知道影响值的外部因素时,或者当获得属性的初始值需要复杂或大量计算时,可以只在需要的时候计算它。
@ -122,7 +122,7 @@ print(manager.importer.fileName)
// 输出 "data.txt” // 输出 "data.txt”
``` ```
> 注意 > 注意
> 如果一个被标记为 `lazy` 的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。 > 如果一个被标记为 `lazy` 的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。
<a name="stored_properties_and_instance_variables"></a> <a name="stored_properties_and_instance_variables"></a>
@ -211,7 +211,7 @@ struct AlternativeRect {
只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。 只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。
> 注意 > 注意
> 必须使用 `var` 关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。`let` 关键字只用来声明常量属性,表示初始化后再也无法修改的值。 > 必须使用 `var` 关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。`let` 关键字只用来声明常量属性,表示初始化后再也无法修改的值。
只读计算属性的声明可以去掉 `get` 关键字和花括号: 只读计算属性的声明可以去掉 `get` 关键字和花括号:
@ -235,7 +235,7 @@ print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
*属性观察器*监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。 *属性观察器*监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。
可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。你不必为非重写的计算属性添加属性观察器,因为可以通过它的 setter 直接监控和响应值的变化。 属性重写请参考[重写](./13_Inheritance.html#overriding)。 可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。你不必为非重写的计算属性添加属性观察器,因为可以通过它的 setter 直接监控和响应值的变化。 属性重写请参考[重写](./13_Inheritance.html#overriding)。
可以为属性添加如下的一个或全部观察器: 可以为属性添加如下的一个或全部观察器:
@ -246,7 +246,7 @@ print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
同样,`didSet` 观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名 `oldValue`。如果在 `didSet` 方法中再次对该属性赋值,那么新值会覆盖旧的值。 同样,`didSet` 观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名 `oldValue`。如果在 `didSet` 方法中再次对该属性赋值,那么新值会覆盖旧的值。
> 注意 > 注意
> 父类的属性在子类的构造器中被赋值时,它在父类中的 `willSet` 和 `didSet` 观察器会被调用,随后才会调用子类的观察器。在父类初始化方法调用之前,子类给属性赋值时,观察器不会被调用。 > 父类的属性在子类的构造器中被赋值时,它在父类中的 `willSet` 和 `didSet` 观察器会被调用,随后才会调用子类的观察器。在父类初始化方法调用之前,子类给属性赋值时,观察器不会被调用。
> 有关构造器代理的更多信息,请参考[值类型的构造器代理](./14_Initialization.html#initializer_delegation_for_value_types)和[类的构造器代理规则](./14_Initialization.html#initializer_delegation_for_class_types)。 > 有关构造器代理的更多信息,请参考[值类型的构造器代理](./14_Initialization.html#initializer_delegation_for_value_types)和[类的构造器代理规则](./14_Initialization.html#initializer_delegation_for_class_types)。
@ -298,9 +298,9 @@ stepCounter.totalSteps = 896
另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器。计算型变量跟计算属性一样,返回一个计算结果而不是存储值,声明格式也完全一样。 另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器。计算型变量跟计算属性一样,返回一个计算结果而不是存储值,声明格式也完全一样。
> 注意 > 注意
> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`lazy`修饰符。 > 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`lazy`修饰符。
> 局部范围的常量或变量从不延迟计算。 > 局部范围的常量或变量从不延迟计算。
<a name="type_properties"></a> <a name="type_properties"></a>
## 类型属性 ## 类型属性
@ -313,8 +313,8 @@ stepCounter.totalSteps = 896
存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算型属性一样只能定义成变量属性。 存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算型属性一样只能定义成变量属性。
> 注意 > 注意
> 跟实例的存储型属性不同,必须给存储型类型属性指定默认值,因为类型本身没有构造器,也就无法在初始化过程中使用构造器给类型属性赋值。 > 跟实例的存储型属性不同,必须给存储型类型属性指定默认值,因为类型本身没有构造器,也就无法在初始化过程中使用构造器给类型属性赋值。
> 存储型类型属性是延迟初始化的,它们只有在第一次被访问的时候才会被初始化。即使它们被多个线程同时访问,系统也保证只会对其进行一次初始化,并且不需要对其使用 `lazy` 修饰符。 > 存储型类型属性是延迟初始化的,它们只有在第一次被访问的时候才会被初始化。即使它们被多个线程同时访问,系统也保证只会对其进行一次初始化,并且不需要对其使用 `lazy` 修饰符。
<a name="type_property_syntax"></a> <a name="type_property_syntax"></a>
@ -348,8 +348,8 @@ class SomeClass {
} }
``` ```
> 注意 > 注意
> 例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟计算型实例属性的语法相同。 > 例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟计算型实例属性的语法相同。
<a name="querying_and_setting_type_properties"></a> <a name="querying_and_setting_type_properties"></a>
### 获取和设置类型属性的值 ### 获取和设置类型属性的值
@ -406,8 +406,8 @@ struct AudioChannel {
- 如果 `currentLevel` 的新值大于允许的阈值 `thresholdLevel`,属性观察器将 `currentLevel` 的值限定为阈值 `thresholdLevel` - 如果 `currentLevel` 的新值大于允许的阈值 `thresholdLevel`,属性观察器将 `currentLevel` 的值限定为阈值 `thresholdLevel`
- 如果修正后的 `currentLevel` 值大于静态类型属性 `maxInputLevelForAllChannels` 的值,属性观察器就将新值保存在 `maxInputLevelForAllChannels` 中。 - 如果修正后的 `currentLevel` 值大于静态类型属性 `maxInputLevelForAllChannels` 的值,属性观察器就将新值保存在 `maxInputLevelForAllChannels` 中。
> 注意 > 注意
> 在第一个检查过程中,`didSet` 属性观察器将 `currentLevel` 设置成了不同的值,但这不会造成属性观察器被再次调用。 > 在第一个检查过程中,`didSet` 属性观察器将 `currentLevel` 设置成了不同的值,但这不会造成属性观察器被再次调用。
可以使用结构体 `AudioChannel` 创建两个声道 `leftChannel``rightChannel`,用以表示立体声系统的音量: 可以使用结构体 `AudioChannel` 创建两个声道 `leftChannel``rightChannel`,用以表示立体声系统的音量:

View File

@ -9,7 +9,7 @@
> 翻译+校对:[DianQK](https://github.com/DianQK) > 翻译+校对:[DianQK](https://github.com/DianQK)
> 2.1 > 2.1
> 翻译:[DianQK](https://github.com/DianQK)[Realank](https://github.com/Realank) 校对:[shanks](http://codebuild.me)2016-01-18 > 翻译:[DianQK](https://github.com/DianQK)[Realank](https://github.com/Realank) 校对:[shanks](http://codebuild.me)2016-01-18
> >
> 2.2 > 2.2
> 校对:[SketchK](https://github.com/SketchK) 2016-05-13 > 校对:[SketchK](https://github.com/SketchK) 2016-05-13
@ -187,8 +187,8 @@ ovenLight.next()
实例方法是被某个类型的实例调用的方法。你也可以定义在类型本身上调用的方法,这种方法就叫做*类型方法*。在方法的`func`关键字之前加上关键字`static`,来指定类型方法。类还可以用关键字`class`来允许子类重写父类的方法实现。 实例方法是被某个类型的实例调用的方法。你也可以定义在类型本身上调用的方法,这种方法就叫做*类型方法*。在方法的`func`关键字之前加上关键字`static`,来指定类型方法。类还可以用关键字`class`来允许子类重写父类的方法实现。
> 注意 > 注意
> 在 Objective-C 中,你只能为 Objective-C 的类类型classes定义类型方法type-level methods。在 Swift 中,你可以为所有的类、结构体和枚举定义类型方法。每一个类型方法都被它所支持的类型显式包含。 > 在 Objective-C 中,你只能为 Objective-C 的类类型classes定义类型方法type-level methods。在 Swift 中,你可以为所有的类、结构体和枚举定义类型方法。每一个类型方法都被它所支持的类型显式包含。
类型方法和实例方法一样用点语法调用。但是,你是在类型上调用这个方法,而不是在实例上调用。下面是如何在`SomeClass`类上调用类型方法的例子: 类型方法和实例方法一样用点语法调用。但是,你是在类型上调用这个方法,而不是在实例上调用。下面是如何在`SomeClass`类上调用类型方法的例子:

View File

@ -9,10 +9,10 @@
> 翻译+校对:[shanks](http://codebuild.me) > 翻译+校对:[shanks](http://codebuild.me)
> 2.1 > 2.1
> 翻译+校对:[shanks](http://codebuild.me)[Realank](https://github.com/Realank) > 翻译+校对:[shanks](http://codebuild.me)[Realank](https://github.com/Realank)
> 2.2 > 2.2
> 校对:[SketchK](https://github.com/SketchK) 2016-05-13 > 校对:[SketchK](https://github.com/SketchK) 2016-05-13
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
> 4.0 > 4.0
@ -73,8 +73,8 @@ print("six times three is \(threeTimesTable[6])")
你可以通过下标访问`threeTimesTable`实例,例如上面演示的`threeTimesTable[6]`。这条语句查询了`3`的乘法表中的第六个元素,返回`3``6`倍即`18` 你可以通过下标访问`threeTimesTable`实例,例如上面演示的`threeTimesTable[6]`。这条语句查询了`3`的乘法表中的第六个元素,返回`3``6`倍即`18`
> 注意 > 注意
> `TimesTable`例子基于一个固定的数学公式,对`threeTimesTable[someIndex]`进行赋值操作并不合适,因此下标定义为只读的。 > `TimesTable`例子基于一个固定的数学公式,对`threeTimesTable[someIndex]`进行赋值操作并不合适,因此下标定义为只读的。
<a name="subscript_usage"></a> <a name="subscript_usage"></a>
## 下标用法 ## 下标用法
@ -92,8 +92,8 @@ numberOfLegs["bird"] = 2
更多关于`Dictionary`下标的信息请参考[读取和修改字典](./04_Collection_Types.html#accessing_and_modifying_a_dictionary) 更多关于`Dictionary`下标的信息请参考[读取和修改字典](./04_Collection_Types.html#accessing_and_modifying_a_dictionary)
> 注意 > 注意
> Swift 的`Dictionary`类型的下标接受并返回可选类型的值。上例中的`numberOfLegs`字典通过下标返回的是一个`Int?`或者说“可选的int”。`Dictionary`类型之所以如此实现下标,是因为不是每个键都有个对应的值,同时这也提供了一种通过键删除对应值的方式,只需将键对应的值赋值为`nil`即可。 > Swift 的`Dictionary`类型的下标接受并返回可选类型的值。上例中的`numberOfLegs`字典通过下标返回的是一个`Int?`或者说“可选的int”。`Dictionary`类型之所以如此实现下标,是因为不是每个键都有个对应的值,同时这也提供了一种通过键删除对应值的方式,只需将键对应的值赋值为`nil`即可。
<a name="subscript_options"></a> <a name="subscript_options"></a>
## 下标选项 ## 下标选项

View File

@ -6,14 +6,14 @@
> 校对:[menlongsheng](https://github.com/menlongsheng) > 校对:[menlongsheng](https://github.com/menlongsheng)
> 2.02.1 > 2.02.1
> 翻译+校对:[shanks](http://codebuild.me) > 翻译+校对:[shanks](http://codebuild.me)
> >
> 2.2 > 2.2
> 校对:[SketchK](https://github.com/SketchK) 2016-05-13 > 校对:[SketchK](https://github.com/SketchK) 2016-05-13
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
> 4.0 > 4.0
> 校对:[kemchenj](https://kemchenj.github.io/) 2017-09-21 > 校对:[kemchenj](https://kemchenj.github.io/) 2017-09-21
本页包含内容: 本页包含内容:
@ -33,7 +33,7 @@
不继承于其它类的类,称之为*基类*。 不继承于其它类的类,称之为*基类*。
> 注意 > 注意
Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。 Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。
下面的例子定义了一个叫`Vehicle`的基类。这个基类声明了一个名为`currentSpeed `,默认值是`0.0`的存储属性(属性类型推断为`Double`)。`currentSpeed`属性的值被一个`String`类型的只读计算型属性`description`使用,用来创建车辆的描述。 下面的例子定义了一个叫`Vehicle`的基类。这个基类声明了一个名为`currentSpeed `,默认值是`0.0`的存储属性(属性类型推断为`Double`)。`currentSpeed`属性的值被一个`String`类型的只读计算型属性`description`使用,用来创建车辆的描述。
@ -179,7 +179,7 @@ train.makeNoise()
你可以将一个继承来的只读属性重写为一个读写属性,只需要在重写版本的属性里提供 getter 和 setter 即可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。 你可以将一个继承来的只读属性重写为一个读写属性,只需要在重写版本的属性里提供 getter 和 setter 即可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。
> 注意 > 注意
如果你在重写属性中提供了 setter那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接通过`super.someProperty`来返回继承来的值,其中`someProperty`是你要重写的属性的名字。 如果你在重写属性中提供了 setter那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接通过`super.someProperty`来返回继承来的值,其中`someProperty`是你要重写的属性的名字。
以下的例子定义了一个新类,叫`Car`,它是`Vehicle`的子类。这个类引入了一个新的存储型属性叫做`gear`,默认值为整数`1``Car`类重写了继承自`Vehicle``description`属性,提供包含当前档位的自定义描述: 以下的例子定义了一个新类,叫`Car`,它是`Vehicle`的子类。这个类引入了一个新的存储型属性叫做`gear`,默认值为整数`1``Car`类重写了继承自`Vehicle``description`属性,提供包含当前档位的自定义描述:
@ -210,8 +210,8 @@ print("Car: \(car.description)")
你可以通过重写属性为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会被通知到,无论那个属性原本是如何实现的。关于属性观察器的更多内容,请看[属性观察器](../chapter2/10_Properties.html#property_observers)。 你可以通过重写属性为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会被通知到,无论那个属性原本是如何实现的。关于属性观察器的更多内容,请看[属性观察器](../chapter2/10_Properties.html#property_observers)。
> 注意 > 注意
你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值是不可以被设置的,所以,为它们提供`willSet``didSet`实现是不恰当。 你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值是不可以被设置的,所以,为它们提供`willSet``didSet`实现是不恰当。
此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已经为那个属性提供了定制的 setter那么你在 setter 中就可以观察到任何值变化了。 此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已经为那个属性提供了定制的 setter那么你在 setter 中就可以观察到任何值变化了。
下面的例子定义了一个新类叫`AutomaticCar`,它是`Car`的子类。`AutomaticCar`表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位: 下面的例子定义了一个新类叫`AutomaticCar`,它是`Car`的子类。`AutomaticCar`表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位:

View File

@ -14,11 +14,11 @@
> 2.2 > 2.2
> 翻译:[pmst](https://github.com/colourful987) > 翻译:[pmst](https://github.com/colourful987)
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-14 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-14
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
> 3.1 > 3.1
> 翻译:[qhd](https://github.com/qhd) 2017-04-18 > 翻译:[qhd](https://github.com/qhd) 2017-04-18
> 4.0 > 4.0
> 翻译:[muhlenXi](https://github.com/muhlenxi) 2017-09-21 > 翻译:[muhlenXi](https://github.com/muhlenxi) 2017-09-21
@ -47,7 +47,7 @@
你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值。以下小节将详细介绍这两种方法。 你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值。以下小节将详细介绍这两种方法。
> 注意 > 注意
当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观察者。 当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观察者。
<a name="initializers"></a> <a name="initializers"></a>
@ -82,7 +82,7 @@ print("The default temperature is \(f.temperature)° Fahrenheit")
如前所述,你可以在构造器中为存储型属性设置初始值。同样,你也可以在属性声明时为其设置默认值。 如前所述,你可以在构造器中为存储型属性设置初始值。同样,你也可以在属性声明时为其设置默认值。
> 注意 > 注意
如果一个属性总是使用相同的初始值,那么为其设置一个默认值比每次都在构造器中赋值要好。两种方法的效果是一样的,只不过使用默认值让属性的初始化和声明结合得更紧密。使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型;同时,它也能让你充分利用默认构造器、构造器继承等特性,后续章节将讲到。 如果一个属性总是使用相同的初始值,那么为其设置一个默认值比每次都在构造器中赋值要好。两种方法的效果是一样的,只不过使用默认值让属性的初始化和声明结合得更紧密。使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型;同时,它也能让你充分利用默认构造器、构造器继承等特性,后续章节将讲到。
你可以使用更简单的方式在定义结构体 `Fahrenheit` 时为属性 `temperature` 设置默认值: 你可以使用更简单的方式在定义结构体 `Fahrenheit` 时为属性 `temperature` 设置默认值:
@ -224,7 +224,7 @@ cheeseQuestion.response = "Yes, I do like cheese."
你可以在构造过程中的任意时间点给常量属性指定一个值,只要在构造过程结束时是一个确定的值。一旦常量属性被赋值,它将永远不可更改。 你可以在构造过程中的任意时间点给常量属性指定一个值,只要在构造过程结束时是一个确定的值。一旦常量属性被赋值,它将永远不可更改。
> 注意 > 注意
对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。 对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。
你可以修改上面的 `SurveyQuestion` 示例,用常量属性替代变量属性 `text`,表示问题内容 `text``SurveyQuestion`的实例被创建之后不会再被修改。尽管 `text` 属性现在是常量,我们仍然可以在类的构造器中设置它的值: 你可以修改上面的 `SurveyQuestion` 示例,用常量属性替代变量属性 `text`,表示问题内容 `text``SurveyQuestion`的实例被创建之后不会再被修改。尽管 `text` 属性现在是常量,我们仍然可以在类的构造器中设置它的值:
@ -293,7 +293,7 @@ let twoByTwo = Size(width: 2.0, height: 2.0)
请注意,如果你为某个值类型定义了一个自定义的构造器,你将无法访问到默认构造器(如果是结构体,还将无法访问逐一成员构造器)。这种限制可以防止你为值类型增加了一个额外的且十分复杂的构造器之后,仍然有人错误的使用自动生成的构造器 请注意,如果你为某个值类型定义了一个自定义的构造器,你将无法访问到默认构造器(如果是结构体,还将无法访问逐一成员构造器)。这种限制可以防止你为值类型增加了一个额外的且十分复杂的构造器之后,仍然有人错误的使用自动生成的构造器
> 注意 > 注意
假如你希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展(`extension`)中,而不是写在值类型的原始定义中。想查看更多内容,请查看[扩展](./21_Extensions.html)章节。 假如你希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展(`extension`)中,而不是写在值类型的原始定义中。想查看更多内容,请查看[扩展](./21_Extensions.html)章节。
下面例子将定义一个结构体 `Rect`,用来代表几何矩形。这个例子需要两个辅助的结构体 `Size``Point`,它们各自为其所有的属性提供了默认初始值 `0.0` 下面例子将定义一个结构体 `Rect`,用来代表几何矩形。这个例子需要两个辅助的结构体 `Size``Point`,它们各自为其所有的属性提供了默认初始值 `0.0`
@ -354,7 +354,7 @@ let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
构造器 `init(center:size:)` 可以直接将 `origin``size` 的新值赋值到对应的属性中。然而,构造器 `init(center:size:)` 通过使用提供了相关功能的现有构造器将会更加便捷。 构造器 `init(center:size:)` 可以直接将 `origin``size` 的新值赋值到对应的属性中。然而,构造器 `init(center:size:)` 通过使用提供了相关功能的现有构造器将会更加便捷。
> 注意 > 注意
如果你想用另外一种不需要自己定义`init()``init(origin:size:)`的方式来实现这个例子,请参考[扩展](./21_Extensions.html)。 如果你想用另外一种不需要自己定义`init()``init(origin:size:)`的方式来实现这个例子,请参考[扩展](./21_Extensions.html)。
<a name="class_inheritance_and_initialization"></a> <a name="class_inheritance_and_initialization"></a>
@ -426,7 +426,7 @@ convenience init(parameters) {
子类中包含两个指定构造器和一个便利构造器。便利构造器必须调用两个指定构造器中的任意一个,因为它只能调用同一个类里的其他构造器。这满足了上面提到的规则 2 和 3。而两个指定构造器必须调用父类中唯一的指定构造器这满足了规则 1。 子类中包含两个指定构造器和一个便利构造器。便利构造器必须调用两个指定构造器中的任意一个,因为它只能调用同一个类里的其他构造器。这满足了上面提到的规则 2 和 3。而两个指定构造器必须调用父类中唯一的指定构造器这满足了规则 1。
> 注意 > 注意
这些规则不会影响类的实例如何创建。任何上图中展示的构造器都可以用来创建完全初始化的实例。这些规则只影响类的构造器如何实现。 这些规则不会影响类的实例如何创建。任何上图中展示的构造器都可以用来创建完全初始化的实例。这些规则只影响类的构造器如何实现。
下面图例中展示了一种涉及四个类的更复杂的类层级结构。它演示了指定构造器是如何在类层级中充当“管道”的作用,在类的构造器链上简化了类之间的相互关系。 下面图例中展示了一种涉及四个类的更复杂的类层级结构。它演示了指定构造器是如何在类层级中充当“管道”的作用,在类的构造器链上简化了类之间的相互关系。
@ -440,7 +440,7 @@ Swift 中类的构造过程包含两个阶段。第一个阶段,类中的每
两段式构造过程的使用让构造过程更安全,同时在整个类层级结构中给予了每个类完全的灵活性。两段式构造过程可以防止属性值在初始化之前被访问,也可以防止属性被另外一个构造器意外地赋予不同的值。 两段式构造过程的使用让构造过程更安全,同时在整个类层级结构中给予了每个类完全的灵活性。两段式构造过程可以防止属性值在初始化之前被访问,也可以防止属性被另外一个构造器意外地赋予不同的值。
> 注意 > 注意
Swift 的两段式构造过程跟 Objective-C 中的构造过程类似。最主要的区别在于阶段 1Objective-C 给每一个属性赋值 `0` 或空值(比如说`0``nil`。Swift 的构造流程则更加灵活,它允许你设置定制的初始值,并自如应对某些属性不能以 `0``nil` 作为合法默认值的情况。 Swift 的两段式构造过程跟 Objective-C 中的构造过程类似。最主要的区别在于阶段 1Objective-C 给每一个属性赋值 `0` 或空值(比如说`0``nil`。Swift 的构造流程则更加灵活,它允许你设置定制的初始值,并自如应对某些属性不能以 `0``nil` 作为合法默认值的情况。
Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造过程不出错地完成: Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造过程不出错地完成:
@ -508,7 +508,7 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
跟 Objective-C 中的子类不同Swift 中的子类默认情况下不会继承父类的构造器。Swift 的这种机制可以防止一个父类的简单构造器被一个更精细的子类继承,并被错误地用来创建子类的实例。 跟 Objective-C 中的子类不同Swift 中的子类默认情况下不会继承父类的构造器。Swift 的这种机制可以防止一个父类的简单构造器被一个更精细的子类继承,并被错误地用来创建子类的实例。
> 注意 > 注意
父类的构造器仅会在安全和适当的情况下被继承。具体内容请参考后续章节[构造器的自动继承](#automatic_initializer_inheritance)。 父类的构造器仅会在安全和适当的情况下被继承。具体内容请参考后续章节[构造器的自动继承](#automatic_initializer_inheritance)。
假如你希望自定义的子类中能提供一个或多个跟父类相同的构造器,你可以在子类中提供这些构造器的自定义实现。 假如你希望自定义的子类中能提供一个或多个跟父类相同的构造器,你可以在子类中提供这些构造器的自定义实现。
@ -517,7 +517,7 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
正如重写属性,方法或者是下标,`override` 修饰符会让编译器去检查父类中是否有相匹配的指定构造器,并验证构造器参数是否正确。 正如重写属性,方法或者是下标,`override` 修饰符会让编译器去检查父类中是否有相匹配的指定构造器,并验证构造器参数是否正确。
> 注意 > 注意
当你重写一个父类的指定构造器时,你总是需要写`override`修饰符,即使是为了实现子类的便利构造器。 当你重写一个父类的指定构造器时,你总是需要写`override`修饰符,即使是为了实现子类的便利构造器。
相反,如果你编写了一个和父类便利构造器相匹配的子类构造器,由于子类不能直接调用父类的便利构造器(每个规则都在上文[类的构造器代理规则](#initializer_delegation_for_class_types)有所描述),因此,严格意义上来讲,你的子类并未对一个父类构造器提供重写。最后的结果就是,你在子类中“重写”一个父类便利构造器时,不需要加 `override` 修饰符。 相反,如果你编写了一个和父类便利构造器相匹配的子类构造器,由于子类不能直接调用父类的便利构造器(每个规则都在上文[类的构造器代理规则](#initializer_delegation_for_class_types)有所描述),因此,严格意义上来讲,你的子类并未对一个父类构造器提供重写。最后的结果就是,你在子类中“重写”一个父类便利构造器时,不需要加 `override` 修饰符。
@ -565,7 +565,7 @@ print("Bicycle: \(bicycle.description)")
// 打印 "Bicycle: 2 wheel(s)" // 打印 "Bicycle: 2 wheel(s)"
``` ```
> 注意 > 注意
子类可以在初始化时修改继承来的变量属性,但是不能修改继承来的常量属性。 子类可以在初始化时修改继承来的变量属性,但是不能修改继承来的常量属性。
<a name="automatic_initializer_inheritance"></a> <a name="automatic_initializer_inheritance"></a>
@ -585,7 +585,7 @@ print("Bicycle: \(bicycle.description)")
即使你在子类中添加了更多的便利构造器,这两条规则仍然适用。 即使你在子类中添加了更多的便利构造器,这两条规则仍然适用。
> 注意 > 注意
对于规则 2子类可以将父类的指定构造器实现为便利构造器。 对于规则 2子类可以将父类的指定构造器实现为便利构造器。
<a name="designated_and_convenience_initializers_in_action"></a> <a name="designated_and_convenience_initializers_in_action"></a>
@ -680,7 +680,7 @@ class ShoppingListItem: RecipeIngredient {
} }
``` ```
> 注意 > 注意
`ShoppingListItem` 没有定义构造器来为 `purchased` 提供初始值,因为添加到购物单的物品的初始状态总是未购买。 `ShoppingListItem` 没有定义构造器来为 `purchased` 提供初始值,因为添加到购物单的物品的初始状态总是未购买。
由于它为自己引入的所有属性都提供了默认值,并且自己没有定义任何构造器,`ShoppingListItem` 将自动继承所有父类中的指定构造器和便利构造器。 由于它为自己引入的所有属性都提供了默认值,并且自己没有定义任何构造器,`ShoppingListItem` 将自动继承所有父类中的指定构造器和便利构造器。
@ -716,15 +716,15 @@ for item in breakfastList {
为了妥善处理这种构造过程中可能会失败的情况。你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在 `init` 关键字后面添加问号 (`init?`)。 为了妥善处理这种构造过程中可能会失败的情况。你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在 `init` 关键字后面添加问号 (`init?`)。
> 注意 > 注意
可失败构造器的参数名和参数类型,不能与其它非可失败构造器的参数名,及其参数类型相同。 可失败构造器的参数名和参数类型,不能与其它非可失败构造器的参数名,及其参数类型相同。
可失败构造器会创建一个类型为自身类型的可选类型的对象。你通过 `return nil` 语句来表明可失败构造器在何种情况下应该 “失败”。 可失败构造器会创建一个类型为自身类型的可选类型的对象。你通过 `return nil` 语句来表明可失败构造器在何种情况下应该 “失败”。
> 注意 > 注意
严格来说,构造器都不支持返回值。因为构造器本身的作用,只是为了确保对象能被正确构造。因此你只是用`return nil`表明可失败构造器构造失败,而不要用关键字`return`来表明构造成功。 严格来说,构造器都不支持返回值。因为构造器本身的作用,只是为了确保对象能被正确构造。因此你只是用`return nil`表明可失败构造器构造失败,而不要用关键字`return`来表明构造成功。
例如,实现针对数字类型转换的可失败构造器。确保数字类型之间的转换能保持精确的值,使用这个 `init(exactly:)` 构造器。如果类型转换不能保持值不变,则这个构造器构造失败。 例如,实现针对数字类型转换的可失败构造器。确保数字类型之间的转换能保持精确的值,使用这个 `init(exactly:)` 构造器。如果类型转换不能保持值不变,则这个构造器构造失败。
``` ```
let wholeNumber: Double = 12345.0 let wholeNumber: Double = 12345.0
@ -781,7 +781,7 @@ if anonymousCreature == nil {
// 打印 "The anonymous creature could not be initialized" // 打印 "The anonymous creature could not be initialized"
``` ```
> 注意 > 注意
空字符串(如 `""`,而不是 `"Giraffe"` )和一个值为 `nil` 的可选类型的字符串是两个完全不同的概念。上例中的空字符串(`""`)其实是一个有效的,非可选类型的字符串。这里我们之所以让 `Animal` 的可失败构造器构造失败,只是因为对于 `Animal` 这个类的 `species` 属性来说,它更适合有一个具体的值,而不是空字符串。 空字符串(如 `""`,而不是 `"Giraffe"` )和一个值为 `nil` 的可选类型的字符串是两个完全不同的概念。上例中的空字符串(`""`)其实是一个有效的,非可选类型的字符串。这里我们之所以让 `Animal` 的可失败构造器构造失败,只是因为对于 `Animal` 这个类的 `species` 属性来说,它更适合有一个具体的值,而不是空字符串。
<a name="failable_nitializers_for_enumerations"></a> <a name="failable_nitializers_for_enumerations"></a>
@ -857,7 +857,7 @@ if unknownUnit == nil {
无论是向上代理还是横向代理,如果你代理到的其他可失败构造器触发构造失败,整个构造过程将立即终止,接下来的任何构造代码不会再被执行。 无论是向上代理还是横向代理,如果你代理到的其他可失败构造器触发构造失败,整个构造过程将立即终止,接下来的任何构造代码不会再被执行。
> 注意 > 注意
可失败构造器也可以代理到其它的非可失败构造器。通过这种方式,你可以增加一个可能的失败状态到现有的构造过程中。 可失败构造器也可以代理到其它的非可失败构造器。通过这种方式,你可以增加一个可能的失败状态到现有的构造过程中。
下面这个例子,定义了一个名为`CartItem``Product`类的子类。这个类建立了一个在线购物车中的物品的模型,它有一个名为`quantity`的常量存储型属性,并确保该属性的值至少为`1` 下面这个例子,定义了一个名为`CartItem``Product`类的子类。这个类建立了一个在线购物车中的物品的模型,它有一个名为`quantity`的常量存储型属性,并确保该属性的值至少为`1`
@ -865,7 +865,7 @@ if unknownUnit == nil {
```swift ```swift
class Product { class Product {
let name: String let name: String
init?(name: String) { init?(name: String) {
if name.isEmpty { return nil } if name.isEmpty { return nil }
self.name = name self.name = name
} }
@ -901,7 +901,7 @@ if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
print("Unable to initialize zero shirts") print("Unable to initialize zero shirts")
} }
// 打印 "Unable to initialize zero shirts" // 打印 "Unable to initialize zero shirts"
``` ```
同样地,如果你尝试传入一个值为空字符串的 `name` 来创建一个 `CartItem` 实例,那么将导致父类 `Product` 的构造过程失败: 同样地,如果你尝试传入一个值为空字符串的 `name` 来创建一个 `CartItem` 实例,那么将导致父类 `Product` 的构造过程失败:
@ -921,7 +921,7 @@ if let oneUnnamed = CartItem(name: "", quantity: 1) {
注意,当你用子类的非可失败构造器重写父类的可失败构造器时,向上代理到父类的可失败构造器的唯一方式是对父类的可失败构造器的返回值进行强制解包。 注意,当你用子类的非可失败构造器重写父类的可失败构造器时,向上代理到父类的可失败构造器的唯一方式是对父类的可失败构造器的返回值进行强制解包。
> 注意 > 注意
你可以用非可失败构造器重写可失败构造器,但反过来却不行。 你可以用非可失败构造器重写可失败构造器,但反过来却不行。
下例定义了一个名为 `Document` 的类,`name` 属性的值必须为一个非空字符串或 `nil`,但不能是一个空字符串: 下例定义了一个名为 `Document` 的类,`name` 属性的值必须为一个非空字符串或 `nil`,但不能是一个空字符串:
@ -1002,7 +1002,7 @@ class SomeSubclass: SomeClass {
} }
``` ```
> 注意 > 注意
如果子类继承的构造器能满足必要构造器的要求,则无须在子类中显式提供必要构造器的实现。 如果子类继承的构造器能满足必要构造器的要求,则无须在子类中显式提供必要构造器的实现。
<a name="setting_a_default_property_value_with_a_closure_or_function"></a> <a name="setting_a_default_property_value_with_a_closure_or_function"></a>
@ -1026,7 +1026,7 @@ class SomeClass {
注意闭包结尾的花括号后面接了一对空的小括号。这用来告诉 Swift 立即执行此闭包。如果你忽略了这对括号,相当于将闭包本身作为值赋值给了属性,而不是将闭包的返回值赋值给属性。 注意闭包结尾的花括号后面接了一对空的小括号。这用来告诉 Swift 立即执行此闭包。如果你忽略了这对括号,相当于将闭包本身作为值赋值给了属性,而不是将闭包的返回值赋值给属性。
> 注意 > 注意
如果你使用闭包来初始化属性,请记住在闭包执行时,实例的其它部分都还没有初始化。这意味着你不能在闭包里访问其它属性,即使这些属性有默认值。同样,你也不能使用隐式的 `self` 属性,或者调用任何实例方法。 如果你使用闭包来初始化属性,请记住在闭包执行时,实例的其它部分都还没有初始化。这意味着你不能在闭包里访问其它属性,即使这些属性有默认值。同样,你也不能使用隐式的 `self` 属性,或者调用任何实例方法。
下面例子中定义了一个结构体 `Chessboard`,它构建了西洋跳棋游戏的棋盘,西洋跳棋游戏在一副黑白格交替的 8 x 8 的棋盘中进行的: 下面例子中定义了一个结构体 `Chessboard`,它构建了西洋跳棋游戏的棋盘,西洋跳棋游戏在一副黑白格交替的 8 x 8 的棋盘中进行的:

View File

@ -12,7 +12,7 @@
> 校对:[shanks](http://codebuild.me)2015-10-31 > 校对:[shanks](http://codebuild.me)2015-10-31
> >
> 2.2 > 2.2
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-14 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-14
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
> 4.0 > 4.0

View File

@ -10,10 +10,10 @@
> 2.1 > 2.1
> 翻译:[Channe](https://github.com/Channe) > 翻译:[Channe](https://github.com/Channe)
> 校对:[shanks](http://codebuild.me)[Realank](https://github.com/Realank) 2016-01-23 > 校对:[shanks](http://codebuild.me)[Realank](https://github.com/Realank) 2016-01-23
> >
> 2.2 > 2.2
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-14 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-14
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
本页包含内容: 本页包含内容:
@ -29,7 +29,7 @@ Swift 使用*自动引用计数ARC*机制来跟踪和管理你的应用程
然而在少数情况下为了能帮助你管理内存ARC 需要更多的,代码之间关系的信息。本章描述了这些情况,并且为你示范怎样才能使 ARC 来管理你的应用程序的所有内存。在 Swift 使用 ARC 与在 Obejctive-C 中使用 ARC 非常类似,具体请参考[过渡到 ARC 的发布说明](https://developer.apple.com/library/content/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226) 然而在少数情况下为了能帮助你管理内存ARC 需要更多的,代码之间关系的信息。本章描述了这些情况,并且为你示范怎样才能使 ARC 来管理你的应用程序的所有内存。在 Swift 使用 ARC 与在 Obejctive-C 中使用 ARC 非常类似,具体请参考[过渡到 ARC 的发布说明](https://developer.apple.com/library/content/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226)
> 注意 > 注意
引用计数仅仅应用于类的实例。结构体和枚举类型是值类型,不是引用类型,也不是通过引用的方式存储和传递。 引用计数仅仅应用于类的实例。结构体和枚举类型是值类型,不是引用类型,也不是通过引用的方式存储和传递。
<a name="how_arc_works"></a> <a name="how_arc_works"></a>
@ -202,7 +202,7 @@ Swift 提供了两种办法用来解决你在使用类的属性时所遇到的
你可以像其他可选值一样,检查弱引用的值是否存在,你将永远不会访问已销毁的实例的引用。 你可以像其他可选值一样,检查弱引用的值是否存在,你将永远不会访问已销毁的实例的引用。
> 注意 > 注意
> 当 ARC 设置弱引用为`nil`时,属性观察不会被触发。 > 当 ARC 设置弱引用为`nil`时,属性观察不会被触发。
下面的例子跟上面`Person``Apartment`的例子一致,但是有一个重要的区别。这一次,`Apartment``tenant`属性被声明为弱引用: 下面的例子跟上面`Person``Apartment`的例子一致,但是有一个重要的区别。这一次,`Apartment``tenant`属性被声明为弱引用:
@ -264,7 +264,7 @@ unit4A = nil
上面的两段代码展示了变量`john``unit4A`在被赋值为`nil`后,`Person`实例和`Apartment`实例的析构函数都打印出“销毁”的信息。这证明了引用循环被打破了。 上面的两段代码展示了变量`john``unit4A`在被赋值为`nil`后,`Person`实例和`Apartment`实例的析构函数都打印出“销毁”的信息。这证明了引用循环被打破了。
> 注意 > 注意
在使用垃圾收集的系统里,弱指针有时用来实现简单的缓冲机制,因为没有强引用的对象只会在内存压力触发垃圾收集时才被销毁。但是在 ARC 中,一旦值的最后一个强引用被移除,就会被立即销毁,这导致弱引用并不适合上面的用途。 在使用垃圾收集的系统里,弱指针有时用来实现简单的缓冲机制,因为没有强引用的对象只会在内存压力触发垃圾收集时才被销毁。但是在 ARC 中,一旦值的最后一个强引用被移除,就会被立即销毁,这导致弱引用并不适合上面的用途。
<a name="unowned_references"></a> <a name="unowned_references"></a>
@ -274,8 +274,8 @@ unit4A = nil
无主引用通常都被期望拥有值。不过 ARC 无法在实例被销毁后将无主引用设为`nil`,因为非可选类型的变量不允许被赋值为`nil` 无主引用通常都被期望拥有值。不过 ARC 无法在实例被销毁后将无主引用设为`nil`,因为非可选类型的变量不允许被赋值为`nil`
> 重要 > 重要
> 使用无主引用,你*必须*确保引用始终指向一个未销毁的实例。 > 使用无主引用,你*必须*确保引用始终指向一个未销毁的实例。
> 如果你试图在实例被销毁后,访问该实例的无主引用,会触发运行时错误。 > 如果你试图在实例被销毁后,访问该实例的无主引用,会触发运行时错误。
下面的例子定义了两个类,`Customer``CreditCard`,模拟了银行客户和客户的信用卡。这两个类中,每一个都将另外一个类的实例作为自身的属性。这种关系可能会造成循环强引用。 下面的例子定义了两个类,`Customer``CreditCard`,模拟了银行客户和客户的信用卡。这两个类中,每一个都将另外一个类的实例作为自身的属性。这种关系可能会造成循环强引用。
@ -309,7 +309,7 @@ class CreditCard {
} }
``` ```
> 注意 > 注意
> `CreditCard`类的`number`属性被定义为`UInt64`类型而不是`Int`类型,以确保`number`属性的存储量在 32 位和 64 位系统上都能足够容纳 16 位的卡号。 > `CreditCard`类的`number`属性被定义为`UInt64`类型而不是`Int`类型,以确保`number`属性的存储量在 32 位和 64 位系统上都能足够容纳 16 位的卡号。
下面的代码片段定义了一个叫`john`的可选类型`Customer`变量,用来保存某个特定客户的引用。由于是可选类型,所以变量被初始化为`nil` 下面的代码片段定义了一个叫`john`的可选类型`Customer`变量,用来保存某个特定客户的引用。由于是可选类型,所以变量被初始化为`nil`
@ -345,7 +345,7 @@ john = nil
最后的代码展示了在`john`变量被设为`nil``Customer`实例和`CreditCard`实例的构造函数都打印出了“销毁”的信息。 最后的代码展示了在`john`变量被设为`nil``Customer`实例和`CreditCard`实例的构造函数都打印出了“销毁”的信息。
> 注意 > 注意
>上面的例子展示了如何使用安全的无主引用。对于需要禁用运行时的安全检查的情况例如出于性能方面的原因Swift还提供了不安全的无主引用。与所有不安全的操作一样你需要负责检查代码以确保其安全性。 >上面的例子展示了如何使用安全的无主引用。对于需要禁用运行时的安全检查的情况例如出于性能方面的原因Swift还提供了不安全的无主引用。与所有不安全的操作一样你需要负责检查代码以确保其安全性。
>你可以通过`unowned(unsafe)`来声明不安全无主引用。如果你试图在实例被销毁后,访问该实例的不安全无主引用,你的程序会尝试访问该实例之前所在的内存地址,这是一个不安全的操作。 >你可以通过`unowned(unsafe)`来声明不安全无主引用。如果你试图在实例被销毁后,访问该实例的不安全无主引用,你的程序会尝试访问该实例之前所在的内存地址,这是一个不安全的操作。
@ -461,7 +461,7 @@ print(heading.asHTML())
// 打印 "<h1>some default text</h1>" // 打印 "<h1>some default text</h1>"
``` ```
> 注意 > 注意
`asHTML`声明为`lazy`属性,因为只有当元素确实需要被处理为 HTML 输出的字符串时,才需要使用`asHTML`。也就是说,在默认的闭包中可以使用`self`,因为只有当初始化完成以及`self`确实存在后,才能访问`lazy`属性。 `asHTML`声明为`lazy`属性,因为只有当元素确实需要被处理为 HTML 输出的字符串时,才需要使用`asHTML`。也就是说,在默认的闭包中可以使用`self`,因为只有当初始化完成以及`self`确实存在后,才能访问`lazy`属性。
`HTMLElement`类只提供了一个构造函数,通过`name``text`(如果有的话)参数来初始化一个新元素。该类也定义了一个析构函数,当`HTMLElement`实例被销毁时,打印一条消息。 `HTMLElement`类只提供了一个构造函数,通过`name``text`(如果有的话)参数来初始化一个新元素。该类也定义了一个析构函数,当`HTMLElement`实例被销毁时,打印一条消息。
@ -474,7 +474,7 @@ print(paragraph!.asHTML())
// 打印 "<p>hello, world</p>" // 打印 "<p>hello, world</p>"
``` ```
> 注意 > 注意
上面的`paragraph`变量定义为可选类型的`HTMLElement`,因此我们可以赋值`nil`给它来演示循环强引用。 上面的`paragraph`变量定义为可选类型的`HTMLElement`,因此我们可以赋值`nil`给它来演示循环强引用。
不幸的是,上面写的`HTMLElement`类产生了类实例和作为`asHTML`默认值的闭包之间的循环强引用。循环强引用如下图所示: 不幸的是,上面写的`HTMLElement`类产生了类实例和作为`asHTML`默认值的闭包之间的循环强引用。循环强引用如下图所示:
@ -483,7 +483,7 @@ print(paragraph!.asHTML())
实例的`asHTML`属性持有闭包的强引用。但是,闭包在其闭包体内使用了`self`(引用了`self.name``self.text`),因此闭包捕获了`self`,这意味着闭包又反过来持有了`HTMLElement`实例的强引用。这样两个对象就产生了循环强引用。(更多关于闭包捕获值的信息,请参考[值捕获](./07_Closures.html#capturing_values))。 实例的`asHTML`属性持有闭包的强引用。但是,闭包在其闭包体内使用了`self`(引用了`self.name``self.text`),因此闭包捕获了`self`,这意味着闭包又反过来持有了`HTMLElement`实例的强引用。这样两个对象就产生了循环强引用。(更多关于闭包捕获值的信息,请参考[值捕获](./07_Closures.html#capturing_values))。
> 注意 > 注意
虽然闭包多次使用了`self`,它只捕获`HTMLElement`实例的一个强引用。 虽然闭包多次使用了`self`,它只捕获`HTMLElement`实例的一个强引用。
如果设置`paragraph`变量为`nil`,打破它持有的`HTMLElement`实例的强引用,`HTMLElement`实例和它的闭包都不会被销毁,也是因为循环强引用: 如果设置`paragraph`变量为`nil`,打破它持有的`HTMLElement`实例的强引用,`HTMLElement`实例和它的闭包都不会被销毁,也是因为循环强引用:
@ -499,7 +499,7 @@ paragraph = nil
在定义闭包时同时定义捕获列表作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的循环强引用。捕获列表定义了闭包体内捕获一个或者多个引用类型的规则。跟解决两个类实例间的循环强引用一样,声明每个捕获的引用为弱引用或无主引用,而不是强引用。应当根据代码关系来决定使用弱引用还是无主引用。 在定义闭包时同时定义捕获列表作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的循环强引用。捕获列表定义了闭包体内捕获一个或者多个引用类型的规则。跟解决两个类实例间的循环强引用一样,声明每个捕获的引用为弱引用或无主引用,而不是强引用。应当根据代码关系来决定使用弱引用还是无主引用。
> 注意 > 注意
Swift 有如下要求:只要在闭包内使用`self`的成员,就要用`self.someProperty`或者`self.someMethod()`(而不只是`someProperty``someMethod()`)。这提醒你可能会一不小心就捕获了`self` Swift 有如下要求:只要在闭包内使用`self`的成员,就要用`self.someProperty`或者`self.someMethod()`(而不只是`someProperty``someMethod()`)。这提醒你可能会一不小心就捕获了`self`
<a name="defining_a_capture_list"></a> <a name="defining_a_capture_list"></a>
@ -532,7 +532,7 @@ lazy var someClosure: Void -> String = {
相反的,在被捕获的引用可能会变为`nil`时,将闭包内的捕获定义为`弱引用`。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为`nil`。这使我们可以在闭包体内检查它们是否存在。 相反的,在被捕获的引用可能会变为`nil`时,将闭包内的捕获定义为`弱引用`。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为`nil`。这使我们可以在闭包体内检查它们是否存在。
> 注意 > 注意
如果被捕获的引用绝对不会变为`nil`,应该用无主引用,而不是弱引用。 如果被捕获的引用绝对不会变为`nil`,应该用无主引用,而不是弱引用。
前面的`HTMLElement`例子中,无主引用是正确的解决循环强引用的方法。这样编写`HTMLElement`类来避免循环强引用: 前面的`HTMLElement`例子中,无主引用是正确的解决循环强引用的方法。这样编写`HTMLElement`类来避免循环强引用:

View File

@ -10,14 +10,14 @@
> 翻译+校对:[lyojo](https://github.com/lyojo) > 翻译+校对:[lyojo](https://github.com/lyojo)
> 2.1 > 2.1
> 校对:[shanks](http://codebuild.me)2015-10-31 > 校对:[shanks](http://codebuild.me)2015-10-31
> >
> 2.2 > 2.2
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-15 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-15
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
> 4.0 > 4.0
> 校对:[kemchenj](https://kemchenj.github.io/) 2017-09-21 > 校对:[kemchenj](https://kemchenj.github.io/) 2017-09-21
本页包含内容: 本页包含内容:
@ -31,7 +31,7 @@
*可选链式调用*是一种可以在当前值可能为`nil`的可选值上请求和调用属性、方法及下标的方法。如果可选值有值,那么调用就会成功;如果可选值是`nil`,那么调用将返回`nil`。多个调用可以连接在一起形成一个调用链,如果其中任何一个节点为`nil`,整个调用链都会失败,即返回`nil` *可选链式调用*是一种可以在当前值可能为`nil`的可选值上请求和调用属性、方法及下标的方法。如果可选值有值,那么调用就会成功;如果可选值是`nil`,那么调用将返回`nil`。多个调用可以连接在一起形成一个调用链,如果其中任何一个节点为`nil`,整个调用链都会失败,即返回`nil`
> 注意 > 注意
Swift 的可选链式调用和 Objective-C 中向`nil`发送消息有些相像,但是 Swift 的可选链式调用可以应用于任意类型,并且能检查调用是否成功。 Swift 的可选链式调用和 Objective-C 中向`nil`发送消息有些相像,但是 Swift 的可选链式调用可以应用于任意类型,并且能检查调用是否成功。
<a name="optional_chaining_as_an_alternative_to_forced_unwrapping"></a> <a name="optional_chaining_as_an_alternative_to_forced_unwrapping"></a>
@ -57,8 +57,8 @@ class Residence {
} }
``` ```
`Residence`有一个`Int`类型的属性`numberOfRooms`,其默认值为`1``Person`具有一个可选的`residence`属性,其类型为`Residence?` `Residence`有一个`Int`类型的属性`numberOfRooms`,其默认值为`1``Person`具有一个可选的`residence`属性,其类型为`Residence?`
假如你创建了一个新的`Person`实例,它的`residence`属性由于是是可选型而将初始化为`nil`,在下面的代码中,`john`有一个值为`nil``residence`属性: 假如你创建了一个新的`Person`实例,它的`residence`属性由于是是可选型而将初始化为`nil`,在下面的代码中,`john`有一个值为`nil``residence`属性:
```swift ```swift
@ -273,7 +273,7 @@ if (john.residence?.address = someAddress) != nil {
通过可选链式调用,我们可以在一个可选值上访问下标,并且判断下标调用是否成功。 通过可选链式调用,我们可以在一个可选值上访问下标,并且判断下标调用是否成功。
> 注意 > 注意
通过可选链式调用访问可选值的下标时,应该将问号放在下标方括号的前面而不是后面。可选链式调用的问号一般直接跟在可选表达式的后面。 通过可选链式调用访问可选值的下标时,应该将问号放在下标方括号的前面而不是后面。可选链式调用的问号一般直接跟在可选表达式的后面。
下面这个例子用下标访问`john.residence`属性存储的`Residence`实例的`rooms`数组中的第一个房间的名称,因为`john.residence``nil`,所以下标调用失败了: 下面这个例子用下标访问`john.residence`属性存储的`Residence`实例的`rooms`数组中的第一个房间的名称,因为`john.residence``nil`,所以下标调用失败了:
@ -404,5 +404,5 @@ if let beginsWithThe =
// 打印 “John's building identifier begins with "The".” // 打印 “John's building identifier begins with "The".”
``` ```
> 注意 > 注意
在上面的例子中,在方法的圆括号后面加上问号是因为你要在`buildingIdentifier()`方法的可选返回值上进行可选链式调用,而不是方法本身。 在上面的例子中,在方法的圆括号后面加上问号是因为你要在`buildingIdentifier()`方法的可选返回值上进行可选链式调用,而不是方法本身。

View File

@ -3,13 +3,13 @@
> 2.1 > 2.1
> 翻译+校对:[lyojo](https://github.com/lyojo) [ray16897188](https://github.com/ray16897188) 2015-10-23 > 翻译+校对:[lyojo](https://github.com/lyojo) [ray16897188](https://github.com/ray16897188) 2015-10-23
> 校对:[shanks](http://codebuild.me) 2015-10-24 > 校对:[shanks](http://codebuild.me) 2015-10-24
> >
> 2.2 > 2.2
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-15 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-15
> >
> 3.0 > 3.0
> 翻译+校对:[shanks](http://codebuild.me) 2016-09-24 > 翻译+校对:[shanks](http://codebuild.me) 2016-09-24
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
> 4.0 > 4.0
@ -27,7 +27,7 @@
举个例子,假如有个从磁盘上的某个文件读取数据并进行处理的任务,该任务会有多种可能失败的情况,包括指定路径下文件并不存在,文件不具有可读权限,或者文件编码格式不兼容。区分这些不同的失败情况可以让程序解决并处理某些错误,然后把它解决不了的错误报告给用户。 举个例子,假如有个从磁盘上的某个文件读取数据并进行处理的任务,该任务会有多种可能失败的情况,包括指定路径下文件并不存在,文件不具有可读权限,或者文件编码格式不兼容。区分这些不同的失败情况可以让程序解决并处理某些错误,然后把它解决不了的错误报告给用户。
> 注意 > 注意
Swift 中的错误处理涉及到错误处理模式,这会用到 Cocoa 和 Objective-C 中的`NSError`。关于这个类的更多信息请参见 [Using Swift with Cocoa and Objective-C (Swift 4)](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中的[错误处理](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-ID10)。 Swift 中的错误处理涉及到错误处理模式,这会用到 Cocoa 和 Objective-C 中的`NSError`。关于这个类的更多信息请参见 [Using Swift with Cocoa and Objective-C (Swift 4)](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中的[错误处理](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-ID10)。
<a name="representing_and_throwing_errors"></a> <a name="representing_and_throwing_errors"></a>
@ -60,7 +60,7 @@ Swift 中有`4`种处理错误的方式。你可以把函数抛出的错误传
当一个函数抛出一个错误时,你的程序流程会发生改变,所以重要的是你能迅速识别代码中会抛出错误的地方。为了标识出这些地方,在调用一个能抛出错误的函数、方法或者构造器之前,加上`try`关键字,或者`try?``try!`这种变体。这些关键字在下面的小节中有具体讲解。 当一个函数抛出一个错误时,你的程序流程会发生改变,所以重要的是你能迅速识别代码中会抛出错误的地方。为了标识出这些地方,在调用一个能抛出错误的函数、方法或者构造器之前,加上`try`关键字,或者`try?``try!`这种变体。这些关键字在下面的小节中有具体讲解。
> 注意 > 注意
> Swift 中的错误处理和其他语言中用`try``catch`和`throw`进行异常处理很像。和其他语言中(包括 Objective-C 的异常处理不同的是Swift 中的错误处理并不涉及解除调用栈,这是一个计算代价高昂的过程。就此而言,`throw`语句的性能特性是可以和`return`语句相媲美的。 > Swift 中的错误处理和其他语言中用`try``catch`和`throw`进行异常处理很像。和其他语言中(包括 Objective-C 的异常处理不同的是Swift 中的错误处理并不涉及解除调用栈,这是一个计算代价高昂的过程。就此而言,`throw`语句的性能特性是可以和`return`语句相媲美的。
<a name="propagating_errors_using_throwing_functions"></a> <a name="propagating_errors_using_throwing_functions"></a>
@ -75,7 +75,7 @@ func cannotThrowErrors() -> String
一个 throwing 函数可以在其内部抛出错误,并将错误传递到函数被调用时的作用域。 一个 throwing 函数可以在其内部抛出错误,并将错误传递到函数被调用时的作用域。
> 注意 > 注意
只有 throwing 函数可以传递错误。任何在某个非 throwing 函数内部抛出的错误只能在函数内部处理。 只有 throwing 函数可以传递错误。任何在某个非 throwing 函数内部抛出的错误只能在函数内部处理。
下面的例子中,`VendingMachine`类有一个`vend(itemNamed:)`方法,如果请求的物品不存在、缺货或者投入金额小于物品价格,该方法就会抛出一个相应的`VendingMachineError` 下面的例子中,`VendingMachine`类有一个`vend(itemNamed:)`方法,如果请求的物品不存在、缺货或者投入金额小于物品价格,该方法就会抛出一个相应的`VendingMachineError`
@ -137,9 +137,9 @@ func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
} }
``` ```
上例中,`buyFavoriteSnack(person:vendingMachine:) `函数会查找某人最喜欢的零食,并通过调用`vend(itemNamed:)`方法来尝试为他们购买。因为`vend(itemNamed:)`方法能抛出错误,所以在调用的它时候在它前面加了`try`关键字。 上例中,`buyFavoriteSnack(person:vendingMachine:) `函数会查找某人最喜欢的零食,并通过调用`vend(itemNamed:)`方法来尝试为他们购买。因为`vend(itemNamed:)`方法能抛出错误,所以在调用的它时候在它前面加了`try`关键字。
`throwing`构造器能像`throwing`函数一样传递错误。例如下面代码中的`PurchasedSnack`构造器在构造过程中调用了throwing函数并且通过传递到它的调用者来处理这些错误。 `throwing`构造器能像`throwing`函数一样传递错误。例如下面代码中的`PurchasedSnack`构造器在构造过程中调用了throwing函数并且通过传递到它的调用者来处理这些错误。
```swift ```swift
struct PurchasedSnack { struct PurchasedSnack {
@ -254,5 +254,5 @@ func processFile(filename: String) throws {
上面的代码使用一条`defer`语句来确保`open(_:)`函数有一个相应的对`close(_:)`函数的调用。 上面的代码使用一条`defer`语句来确保`open(_:)`函数有一个相应的对`close(_:)`函数的调用。
> 注意 > 注意
> 即使没有涉及到错误处理,你也可以使用`defer`语句。 > 即使没有涉及到错误处理,你也可以使用`defer`语句。

View File

@ -12,7 +12,7 @@
> 校对:[shanks](http://codebuild.me)2015-11-01 > 校对:[shanks](http://codebuild.me)2015-11-01
> >
> 2.2 > 2.2
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-16 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-16
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
> 4.0 > 4.0
@ -153,7 +153,7 @@ for item in library {
若向下转型成功,然后 `movie` 的属性将用于打印一个 `Movie` 实例的描述,包括它的导演的名字 `director`。相似的原理被用来检测 `Song` 实例,当 `Song` 被找到时则打印它的描述(包含 `artist` 的名字)。 若向下转型成功,然后 `movie` 的属性将用于打印一个 `Movie` 实例的描述,包括它的导演的名字 `director`。相似的原理被用来检测 `Song` 实例,当 `Song` 被找到时则打印它的描述(包含 `artist` 的名字)。
> 注意 > 注意
> 转换没有真的改变实例或它的值。根本的实例保持不变;只是简单地把它作为它被转换成的类型来使用。 > 转换没有真的改变实例或它的值。根本的实例保持不变;只是简单地把它作为它被转换成的类型来使用。
<a name="type_casting_for_any_and_anyobject"></a> <a name="type_casting_for_any_and_anyobject"></a>
@ -221,7 +221,7 @@ for thing in things {
// Hello, Michael // Hello, Michael
``` ```
> 注意 > 注意
> `Any`类型可以表示所有类型的值包括可选类型。Swift 会在你用`Any`类型来表示一个可选值的时候,给你一个警告。如果你确实想使用`Any`类型来承载可选值,你可以使用`as`操作符显式转换为`Any`,如下所示: > `Any`类型可以表示所有类型的值包括可选类型。Swift 会在你用`Any`类型来表示一个可选值的时候,给你一个警告。如果你确实想使用`Any`类型来承载可选值,你可以使用`as`操作符显式转换为`Any`,如下所示:
> >
```swift ```swift

View File

@ -12,7 +12,7 @@
> 校对:[shanks](http://codebuild.me)2015-11-01 > 校对:[shanks](http://codebuild.me)2015-11-01
> >
> 2.2 > 2.2
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-16 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-16
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
> 4.0 > 4.0

View File

@ -12,7 +12,7 @@
> 校对:[shanks](http://codebuild.me) > 校对:[shanks](http://codebuild.me)
> >
> 2.2 > 2.2
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-16 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-16
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
> 4.0 > 4.0
@ -40,7 +40,7 @@ Swift 中的扩展可以:
在 Swift 中,你甚至可以对协议进行扩展,提供协议要求的实现,或者添加额外的功能,从而可以让符合协议的类型拥有这些功能。你可以从[协议扩展](./22_Protocols.html#protocol_extensions)获取更多的细节。 在 Swift 中,你甚至可以对协议进行扩展,提供协议要求的实现,或者添加额外的功能,从而可以让符合协议的类型拥有这些功能。你可以从[协议扩展](./22_Protocols.html#protocol_extensions)获取更多的细节。
> 注意 > 注意
扩展可以为一个类型添加新的功能,但是不能重写已有的功能。 扩展可以为一个类型添加新的功能,但是不能重写已有的功能。
<a name="extension_syntax"></a> <a name="extension_syntax"></a>
@ -64,7 +64,7 @@ extension SomeType: SomeProtocol, AnotherProctocol {
通过这种方式添加协议一致性的详细描述请参阅[利用扩展添加协议一致性](./22_Protocols.html#adding_protocol_conformance_with_an_extension)。 通过这种方式添加协议一致性的详细描述请参阅[利用扩展添加协议一致性](./22_Protocols.html#adding_protocol_conformance_with_an_extension)。
> 注意 > 注意
如果你通过扩展为一个已有类型添加新功能,那么新功能对该类型的所有已有实例都是可用的,即使它们是在这个扩展定义之前创建的。 如果你通过扩展为一个已有类型添加新功能,那么新功能对该类型的所有已有实例都是可用的,即使它们是在这个扩展定义之前创建的。
<a name="computed_properties"></a> <a name="computed_properties"></a>
@ -102,18 +102,18 @@ print("A marathon is \(aMarathon) meters long")
// 打印 “A marathon is 42195.0 meters long” // 打印 “A marathon is 42195.0 meters long”
``` ```
> 注意 > 注意
扩展可以添加新的计算型属性,但是不可以添加存储型属性,也不可以为已有属性添加属性观察器。 扩展可以添加新的计算型属性,但是不可以添加存储型属性,也不可以为已有属性添加属性观察器。
<a name="initializers"></a> <a name="initializers"></a>
## 构造器 ## 构造器
扩展可以为已有类型添加新的构造器。这可以让你扩展其它类型,将你自己的定制类型作为其构造器参数,或者提供该类型的原始实现中未提供的额外初始化选项。 扩展可以为已有类型添加新的构造器。这可以让你扩展其它类型,将你自己的定制类型作为其构造器参数,或者提供该类型的原始实现中未提供的额外初始化选项。
扩展能为类添加新的便利构造器,但是它们不能为类添加新的指定构造器或析构器。指定构造器和析构器必须总是由原始的类实现来提供。 扩展能为类添加新的便利构造器,但是它们不能为类添加新的指定构造器或析构器。指定构造器和析构器必须总是由原始的类实现来提供。
> 注意 > 注意
如果你使用扩展为一个值类型添加构造器,同时该值类型的原始实现中未定义任何定制的构造器且所有存储属性提供了默认值,那么我们就可以在扩展中的构造器里调用默认构造器和逐一成员构造器。 如果你使用扩展为一个值类型添加构造器,同时该值类型的原始实现中未定义任何定制的构造器且所有存储属性提供了默认值,那么我们就可以在扩展中的构造器里调用默认构造器和逐一成员构造器。
正如在[值类型的构造器代理](./14_Initialization.html#initializer_delegation_for_value_types)中描述的,如果你把定制的构造器写在值类型的原始实现中,上述规则将不再适用。 正如在[值类型的构造器代理](./14_Initialization.html#initializer_delegation_for_value_types)中描述的,如果你把定制的构造器写在值类型的原始实现中,上述规则将不再适用。
下面的例子定义了一个用于描述几何矩形的结构体 `Rect`。这个例子同时定义了两个辅助结构体 `Size``Point`,它们都把 `0.0` 作为所有属性的默认值: 下面的例子定义了一个用于描述几何矩形的结构体 `Rect`。这个例子同时定义了两个辅助结构体 `Size``Point`,它们都把 `0.0` 作为所有属性的默认值:
@ -158,7 +158,7 @@ let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
// centerRect 的原点是 (2.5, 2.5),大小是 (3.0, 3.0) // centerRect 的原点是 (2.5, 2.5),大小是 (3.0, 3.0)
``` ```
> 注意 > 注意
如果你使用扩展提供了一个新的构造器,你依旧有责任确保构造过程能够让实例完全初始化。 如果你使用扩展提供了一个新的构造器,你依旧有责任确保构造过程能够让实例完全初始化。
<a name="methods"></a> <a name="methods"></a>
@ -305,5 +305,5 @@ printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
函数 `printIntegerKinds(_:)` 接受一个 `Int` 数组,然后对该数组进行迭代。在每次迭代过程中,对当前整数的计算型属性 `kind` 的值进行评估,并打印出适当的描述。 函数 `printIntegerKinds(_:)` 接受一个 `Int` 数组,然后对该数组进行迭代。在每次迭代过程中,对当前整数的计算型属性 `kind` 的值进行评估,并打印出适当的描述。
> 注意 > 注意
由于已知 `number.kind``Int.Kind` 类型,因此在 `switch` 语句中,`Int.Kind` 中的所有成员值都可以使用简写形式,例如使用 `. Negative` 而不是 `Int.Kind.Negative` 由于已知 `number.kind``Int.Kind` 类型,因此在 `switch` 语句中,`Int.Kind` 中的所有成员值都可以使用简写形式,例如使用 `. Negative` 而不是 `Int.Kind.Negative`

View File

@ -16,7 +16,7 @@
> 翻译+校对:[SketchK](https://github.com/SketchK) > 翻译+校对:[SketchK](https://github.com/SketchK)
> >
> 3.0 > 3.0
> 校对:[CMB](https://github.com/chenmingbiao)版本日期2016-09-13 > 校对:[CMB](https://github.com/chenmingbiao)版本日期2016-09-13
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
本页包含内容: 本页包含内容:
@ -189,7 +189,7 @@ print("And another one: \(generator.random())")
如果你在协议中定义了一个实例方法,该方法会改变遵循该协议的类型的实例,那么在定义协议时需要在方法前加 `mutating` 关键字。这使得结构体和枚举能够遵循此协议并满足此方法要求。 如果你在协议中定义了一个实例方法,该方法会改变遵循该协议的类型的实例,那么在定义协议时需要在方法前加 `mutating` 关键字。这使得结构体和枚举能够遵循此协议并满足此方法要求。
> 注意 > 注意
> 实现协议中的 `mutating` 方法时,若是类类型,则不用写 `mutating` 关键字。而对于结构体和枚举,则必须写 `mutating` 关键字。 > 实现协议中的 `mutating` 方法时,若是类类型,则不用写 `mutating` 关键字。而对于结构体和枚举,则必须写 `mutating` 关键字。
如下所示,`Togglable` 协议只要求实现一个名为 `toggle` 的实例方法。根据名称的暗示,`toggle()` 方法将改变实例属性,从而切换遵循该协议类型的实例的状态。 如下所示,`Togglable` 协议只要求实现一个名为 `toggle` 的实例方法。根据名称的暗示,`toggle()` 方法将改变实例属性,从而切换遵循该协议类型的实例的状态。
@ -250,7 +250,7 @@ class SomeClass: SomeProtocol {
关于 `required` 构造器的更多内容,请参考[必要构造器](./14_Initialization.html#required_initializers)。 关于 `required` 构造器的更多内容,请参考[必要构造器](./14_Initialization.html#required_initializers)。
> 注意 > 注意
> 如果类已经被标记为 `final`,那么不需要在协议构造器的实现中使用 `required` 修饰符,因为 `final` 类不能有子类。关于 `final` 修饰符的更多内容,请参见[防止重写](./13_Inheritance.html#preventing_overrides)。 > 如果类已经被标记为 `final`,那么不需要在协议构造器的实现中使用 `required` 修饰符,因为 `final` 类不能有子类。关于 `final` 修饰符的更多内容,请参见[防止重写](./13_Inheritance.html#preventing_overrides)。
如果一个子类重写了父类的指定构造器,并且该构造器满足了某个协议的要求,那么该构造器的实现需要同时标注 `required``override` 修饰符: 如果一个子类重写了父类的指定构造器,并且该构造器满足了某个协议的要求,那么该构造器的实现需要同时标注 `required``override` 修饰符:
@ -292,7 +292,7 @@ class SomeSubClass: SomeSuperClass, SomeProtocol {
* 作为常量、变量或属性的类型 * 作为常量、变量或属性的类型
* 作为数组、字典或其他容器中的元素类型 * 作为数组、字典或其他容器中的元素类型
> 注意 > 注意
> 协议是一种类型,因此协议类型的名称应与其他类型(例如 `Int``Double``String`)的写法相同,使用大写字母开头的驼峰式写法,例如(`FullyNamed` 和 `RandomNumberGenerator`)。 > 协议是一种类型,因此协议类型的名称应与其他类型(例如 `Int``Double``String`)的写法相同,使用大写字母开头的驼峰式写法,例如(`FullyNamed` 和 `RandomNumberGenerator`)。
下面是将协议作为类型使用的例子: 下面是将协议作为类型使用的例子:
@ -450,7 +450,7 @@ game.play()
即便无法修改源代码,依然可以通过扩展令已有类型遵循并符合协议。扩展可以为已有类型添加属性、方法、下标以及构造器,因此可以符合协议中的相应要求。详情请在[扩展](./21_Extensions.html)章节中查看。 即便无法修改源代码,依然可以通过扩展令已有类型遵循并符合协议。扩展可以为已有类型添加属性、方法、下标以及构造器,因此可以符合协议中的相应要求。详情请在[扩展](./21_Extensions.html)章节中查看。
> 注意 > 注意
> 通过扩展令已有类型遵循并符合协议时,该类型的所有实例也会随之获得协议中定义的各项功能。 > 通过扩展令已有类型遵循并符合协议时,该类型的所有实例也会随之获得协议中定义的各项功能。
例如下面这个 `TextRepresentable` 协议,任何想要通过文本表示一些内容的类型都可以实现该协议。这些想要表示的内容可以是实例本身的描述,也可以是实例当前状态的文本描述: 例如下面这个 `TextRepresentable` 协议,任何想要通过文本表示一些内容的类型都可以实现该协议。这些想要表示的内容可以是实例本身的描述,也可以是实例当前状态的文本描述:
@ -517,7 +517,7 @@ print(somethingTextRepresentable.textualDescription)
// 打印 “A hamster named Simon” // 打印 “A hamster named Simon”
``` ```
> 注意 > 注意
> 即使满足了协议的所有要求,类型也不会自动遵循协议,必须显式地遵循协议。 > 即使满足了协议的所有要求,类型也不会自动遵循协议,必须显式地遵循协议。
<a name="collections_of_protocol_types"></a> <a name="collections_of_protocol_types"></a>
@ -611,7 +611,7 @@ protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
在以上例子中,协议 `SomeClassOnlyProtocol` 只能被类类型遵循。如果尝试让结构体或枚举类型遵循该协议,则会导致编译错误。 在以上例子中,协议 `SomeClassOnlyProtocol` 只能被类类型遵循。如果尝试让结构体或枚举类型遵循该协议,则会导致编译错误。
> 注意 > 注意
> 当协议定义的要求需要遵循协议的类型必须是引用语义而非值语义时,应该采用类类型专属协议。关于引用语义和值语义的更多内容,请查看[结构体和枚举是值类型](./09_Classes_and_Structures.html#structures_and_enumerations_are_value_types)和[类是引用类型](./09_Classes_and_Structures.html#classes_are_reference_types)。 > 当协议定义的要求需要遵循协议的类型必须是引用语义而非值语义时,应该采用类类型专属协议。关于引用语义和值语义的更多内容,请查看[结构体和枚举是值类型](./09_Classes_and_Structures.html#structures_and_enumerations_are_value_types)和[类是引用类型](./09_Classes_and_Structures.html#classes_are_reference_types)。
<a name="protocol_composition"></a> <a name="protocol_composition"></a>
@ -771,7 +771,7 @@ for object in objects {
`CounterDataSource` 协议定义了一个可选方法 `increment(forCount:)` 和一个可选属性 `fiexdIncrement`,它们使用了不同的方法来从数据源中获取适当的增量值。 `CounterDataSource` 协议定义了一个可选方法 `increment(forCount:)` 和一个可选属性 `fiexdIncrement`,它们使用了不同的方法来从数据源中获取适当的增量值。
> 注意 > 注意
> 严格来讲,`CounterDataSource` 协议中的方法和属性都是可选的,因此遵循协议的类可以不实现这些要求,尽管技术上允许这样做,不过最好不要这样写。 > 严格来讲,`CounterDataSource` 协议中的方法和属性都是可选的,因此遵循协议的类可以不实现这些要求,尽管技术上允许这样做,不过最好不要这样写。
`Counter` 类含有 `CounterDataSource?` 类型的可选属性 `dataSource`,如下所示: `Counter` 类含有 `CounterDataSource?` 类型的可选属性 `dataSource`,如下所示:
@ -891,7 +891,7 @@ print("And here's a random Boolean: \(generator.randomBool())")
可以通过协议扩展来为协议要求的属性、方法以及下标提供默认的实现。如果遵循协议的类型为这些要求提供了自己的实现,那么这些自定义实现将会替代扩展中的默认实现被使用。 可以通过协议扩展来为协议要求的属性、方法以及下标提供默认的实现。如果遵循协议的类型为这些要求提供了自己的实现,那么这些自定义实现将会替代扩展中的默认实现被使用。
> 注意 > 注意
> 通过协议扩展为协议要求提供的默认实现和可选的协议要求不同。虽然在这两种情况下,遵循协议的类型都无需自己实现这些要求,但是通过扩展提供的默认实现可以直接调用,而无需使用可选链式调用。 > 通过协议扩展为协议要求提供的默认实现和可选的协议要求不同。虽然在这两种情况下,遵循协议的类型都无需自己实现这些要求,但是通过扩展提供的默认实现可以直接调用,而无需使用可选链式调用。
例如,`PrettyTextRepresentable` 协议继承自 `TextRepresentable` 协议,可以为其提供一个默认的 `prettyTextualDescription` 属性,只是简单地返回 `textualDescription` 属性的值: 例如,`PrettyTextRepresentable` 协议继承自 `TextRepresentable` 协议,可以为其提供一个默认的 `prettyTextualDescription` 属性,只是简单地返回 `textualDescription` 属性的值:
@ -938,5 +938,5 @@ print(hamsters.textualDescription)
// 打印 “[A hamster named Murray, A hamster named Morgan, A hamster named Maurice]” // 打印 “[A hamster named Murray, A hamster named Morgan, A hamster named Maurice]”
``` ```
> 注意 > 注意
> 如果多个协议扩展都为同一个协议要求提供了默认实现,而遵循协议的类型又同时满足这些协议扩展的限制条件,那么将会使用限制条件最多的那个协议扩展提供的默认实现。 > 如果多个协议扩展都为同一个协议要求提供了默认实现,而遵循协议的类型又同时满足这些协议扩展的限制条件,那么将会使用限制条件最多的那个协议扩展提供的默认实现。

View File

@ -14,10 +14,10 @@
> 2.2:翻译+校对:[Lanford](https://github.com/LanfordCai)2016-04-08 [SketchK](https://github.com/SketchK) 2016-05-16 > 2.2:翻译+校对:[Lanford](https://github.com/LanfordCai)2016-04-08 [SketchK](https://github.com/SketchK) 2016-05-16
> 3.0:翻译+校对:[chenmingjia](https://github.com/chenmingjia)2016-09-12 > 3.0:翻译+校对:[chenmingjia](https://github.com/chenmingjia)2016-09-12
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
> 3.1:翻译:[qhd](https://github.com/qhd)2017-04-10 > 3.1:翻译:[qhd](https://github.com/qhd)2017-04-10
> 4.0 > 4.0
> 翻译+校对:[kemchenj](https://kemchenj.github.io/) 2017-09-21 > 翻译+校对:[kemchenj](https://kemchenj.github.io/) 2017-09-21
@ -86,7 +86,7 @@ func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
在实际应用中,通常需要一个更实用更灵活的函数来交换两个任意类型的值,幸运的是,泛型代码帮你解决了这种问题。(这些函数的泛型版本已经在下面定义好了。) 在实际应用中,通常需要一个更实用更灵活的函数来交换两个任意类型的值,幸运的是,泛型代码帮你解决了这种问题。(这些函数的泛型版本已经在下面定义好了。)
> 注意 > 注意
在上面三个函数中,`a``b` 类型必须相同。如果 `a``b` 类型不同那它们俩就不能互换值。Swift 是类型安全的语言,所以它不允许一个 `String` 类型的变量和一个 `Double` 类型的变量互换值。试图这样做将导致编译错误。 在上面三个函数中,`a``b` 类型必须相同。如果 `a``b` 类型不同那它们俩就不能互换值。Swift 是类型安全的语言,所以它不允许一个 `String` 类型的变量和一个 `Double` 类型的变量互换值。试图这样做将导致编译错误。
<a name="generic_functions"></a> <a name="generic_functions"></a>
@ -130,7 +130,7 @@ swapTwoValues(&someString, &anotherString)
// someString 现在 "world", and anotherString 现在 "hello" // someString 现在 "world", and anotherString 现在 "hello"
``` ```
> 注意 > 注意
上面定义的 `swapTwoValues(_:_:)` 函数是受 `swap(_:_:)` 函数启发而实现的。后者存在于 Swift 标准库,你可以在你的应用程序中使用它。如果你在代码中需要类似 `swapTwoValues(_:_:)` 函数的功能,你可以使用已存在的 `swap(_:_:)` 函数。 上面定义的 `swapTwoValues(_:_:)` 函数是受 `swap(_:_:)` 函数启发而实现的。后者存在于 Swift 标准库,你可以在你的应用程序中使用它。如果你在代码中需要类似 `swapTwoValues(_:_:)` 函数的功能,你可以使用已存在的 `swap(_:_:)` 函数。
<a name="type_parameters"></a> <a name="type_parameters"></a>
@ -147,7 +147,7 @@ swapTwoValues(&someString, &anotherString)
在大多数情况下,类型参数具有一个描述性名字,例如 `Dictionary<Key, Value>` 中的 `Key``Value`,以及 `Array<Element>` 中的 `Element`,这可以告诉阅读代码的人这些类型参数和泛型函数之间的关系。然而,当它们之间没有有意义的关系时,通常使用单个字母来命名,例如 `T``U``V`,正如上面演示的 `swapTwoValues(_:_:)` 函数中的 `T` 一样。 在大多数情况下,类型参数具有一个描述性名字,例如 `Dictionary<Key, Value>` 中的 `Key``Value`,以及 `Array<Element>` 中的 `Element`,这可以告诉阅读代码的人这些类型参数和泛型函数之间的关系。然而,当它们之间没有有意义的关系时,通常使用单个字母来命名,例如 `T``U``V`,正如上面演示的 `swapTwoValues(_:_:)` 函数中的 `T` 一样。
> 注意 > 注意
请始终使用大写字母开头的驼峰命名法(例如 `T``MyTypeParameter`)来为类型参数命名,以表明它们是占位类型,而不是一个值。 请始终使用大写字母开头的驼峰命名法(例如 `T``MyTypeParameter`)来为类型参数命名,以表明它们是占位类型,而不是一个值。
<a name="generic_types"></a> <a name="generic_types"></a>
@ -157,7 +157,7 @@ swapTwoValues(&someString, &anotherString)
这部分内容将向你展示如何编写一个名为 `Stack` (栈)的泛型集合类型。栈是一系列值的有序集合,和 `Array` 类似,但它相比 Swift 的 `Array` 类型有更多的操作限制。数组允许在数组的任意位置插入新元素或是删除其中任意位置的元素。而栈只允许在集合的末端添加新的元素(称之为入*栈*)。类似的,栈也只能从末端移除元素(称之为*出*栈)。 这部分内容将向你展示如何编写一个名为 `Stack` (栈)的泛型集合类型。栈是一系列值的有序集合,和 `Array` 类似,但它相比 Swift 的 `Array` 类型有更多的操作限制。数组允许在数组的任意位置插入新元素或是删除其中任意位置的元素。而栈只允许在集合的末端添加新的元素(称之为入*栈*)。类似的,栈也只能从末端移除元素(称之为*出*栈)。
> 注意 > 注意
栈的概念已被 `UINavigationController` 类用来构造视图控制器的导航结构。你通过调用 `UINavigationController``pushViewController(_:animated:)` 方法来添加新的视图控制器到导航栈,通过 `popViewControllerAnimated(_:)` 方法来从导航栈中移除视图控制器。每当你需要一个严格的“后进先出”方式来管理集合,栈都是最实用的模型。 栈的概念已被 `UINavigationController` 类用来构造视图控制器的导航结构。你通过调用 `UINavigationController``pushViewController(_:animated:)` 方法来添加新的视图控制器到导航栈,通过 `popViewControllerAnimated(_:)` 方法来从导航栈中移除视图控制器。每当你需要一个严格的“后进先出”方式来管理集合,栈都是最实用的模型。
下图展示了一个栈的入栈push和出栈pop的行为 下图展示了一个栈的入栈push和出栈pop的行为
@ -564,7 +564,7 @@ if allItemsMatch(stackOfStrings, arrayOfStrings) {
<a name="extensions_with_a_generic_where_clause"></a> <a name="extensions_with_a_generic_where_clause"></a>
## 具有泛型 where 子句的扩展 ## 具有泛型 where 子句的扩展
你也可以使用泛型 `where` 子句作为扩展的一部分。基于以前的例子,下面的示例扩展了泛型 `Stack` 结构体,添加一个 `isTop(_:)` 方法。 你也可以使用泛型 `where` 子句作为扩展的一部分。基于以前的例子,下面的示例扩展了泛型 `Stack` 结构体,添加一个 `isTop(_:)` 方法。
```swift ```swift
extension Stack where Element: Equatable { extension Stack where Element: Equatable {
@ -577,9 +577,9 @@ extension Stack where Element: Equatable {
} }
``` ```
这个新的 `isTop(_:)` 方法首先检查这个栈是不是空的,然后比较给定的元素与栈顶部的元素。如果你尝试不用泛型 `where` 子句,会有一个问题:在 `isTop(_:)` 里面使用了 `==` 运算符,但是 `Stack` 的定义没有要求它的元素是符合 Equatable 协议的,所以使用 `==` 运算符导致编译时错误。使用泛型 `where` 子句可以为扩展添加新的条件,因此只有当栈中的元素符合 Equatable 协议时,扩展才会添加 `isTop(_:)` 方法。 这个新的 `isTop(_:)` 方法首先检查这个栈是不是空的,然后比较给定的元素与栈顶部的元素。如果你尝试不用泛型 `where` 子句,会有一个问题:在 `isTop(_:)` 里面使用了 `==` 运算符,但是 `Stack` 的定义没有要求它的元素是符合 Equatable 协议的,所以使用 `==` 运算符导致编译时错误。使用泛型 `where` 子句可以为扩展添加新的条件,因此只有当栈中的元素符合 Equatable 协议时,扩展才会添加 `isTop(_:)` 方法。
以下是 `isTop(_:)` 方法的调用方式: 以下是 `isTop(_:)` 方法的调用方式:
```swift ```swift
if stackOfStrings.isTop("tres") { if stackOfStrings.isTop("tres") {
@ -590,7 +590,7 @@ if stackOfStrings.isTop("tres") {
// 打印 "Top element is tres." // 打印 "Top element is tres."
``` ```
如果尝试在其元素不符合 Equatable 协议的栈上调用 `isTop(_:)` 方法,则会收到编译时错误。 如果尝试在其元素不符合 Equatable 协议的栈上调用 `isTop(_:)` 方法,则会收到编译时错误。
```swift ```swift
struct NotEquatable { } struct NotEquatable { }
@ -600,7 +600,7 @@ notEquatableStack.push(notEquatableValue)
notEquatableStack.isTop(notEquatableValue) // 报错 notEquatableStack.isTop(notEquatableValue) // 报错
``` ```
你可以使用泛型 `where` 子句去扩展一个协议。基于以前的示例,下面的示例扩展了 `Container` 协议,添加一个 `startsWith(_:)` 方法。 你可以使用泛型 `where` 子句去扩展一个协议。基于以前的示例,下面的示例扩展了 `Container` 协议,添加一个 `startsWith(_:)` 方法。
```swift ```swift
extension Container where Item: Equatable { extension Container where Item: Equatable {
@ -610,7 +610,7 @@ extension Container where Item: Equatable {
} }
``` ```
这个 `startsWith(_:)` 方法首先确保容器至少有一个元素,然后检查容器中的第一个元素是否与给定的元素相等。任何符合 `Container` 协议的类型都可以使用这个新的 `startsWith(_:)` 方法,包括上面使用的栈和数组,只要容器的元素是符合 Equatable 协议的。 这个 `startsWith(_:)` 方法首先确保容器至少有一个元素,然后检查容器中的第一个元素是否与给定的元素相等。任何符合 `Container` 协议的类型都可以使用这个新的 `startsWith(_:)` 方法,包括上面使用的栈和数组,只要容器的元素是符合 Equatable 协议的。
```swift ```swift
if [9, 9, 9].startsWith(42) { if [9, 9, 9].startsWith(42) {
@ -621,7 +621,7 @@ if [9, 9, 9].startsWith(42) {
// 打印 "Starts with something else." // 打印 "Starts with something else."
``` ```
上述示例中的泛型 `where` 子句要求 `Item` 符合协议,但也可以编写一个泛型 `where` 子句去要求 `Item` 为特定类型。例如: 上述示例中的泛型 `where` 子句要求 `Item` 符合协议,但也可以编写一个泛型 `where` 子句去要求 `Item` 为特定类型。例如:
```swift ```swift
extension Container where Item == Double { extension Container where Item == Double {
@ -637,7 +637,7 @@ print([1260.0, 1200.0, 98.6, 37.0].average())
// 打印 "648.9" // 打印 "648.9"
``` ```
此示例将一个 `average()` 方法添加到 `Item` 类型为 `Double` 的容器中。此方法遍历容器中的元素将其累加,并除以容器的数量计算平均值。它将数量从 `Int` 转换为 `Double` 确保能够进行浮点除法。 此示例将一个 `average()` 方法添加到 `Item` 类型为 `Double` 的容器中。此方法遍历容器中的元素将其累加,并除以容器的数量计算平均值。它将数量从 `Int` 转换为 `Double` 确保能够进行浮点除法。
就像可以在其他地方写泛型 `where` 子句一样,你可以在一个泛型 `where` 子句中包含多个条件作为扩展的一部分。用逗号分隔列表中的每个条件。 就像可以在其他地方写泛型 `where` 子句一样,你可以在一个泛型 `where` 子句中包含多个条件作为扩展的一部分。用逗号分隔列表中的每个条件。

View File

@ -13,7 +13,7 @@
> 校对:[shanks](http://codebuild.me)2015-11-01 > 校对:[shanks](http://codebuild.me)2015-11-01
> >
> 2.2 > 2.2
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-17 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-17
> 3.0.1 > 3.0.1
> 翻译+校对: shanks2016-11-13 > 翻译+校对: shanks2016-11-13
@ -41,7 +41,7 @@
Swift 不仅提供了多种不同的访问级别,还为某些典型场景提供了默认的访问级别,这样就不需要我们在每段代码中都申明显式访问级别。其实,如果只是开发一个单一 target 的应用程序,我们完全可以不用显式声明代码的访问级别。 Swift 不仅提供了多种不同的访问级别,还为某些典型场景提供了默认的访问级别,这样就不需要我们在每段代码中都申明显式访问级别。其实,如果只是开发一个单一 target 的应用程序,我们完全可以不用显式声明代码的访问级别。
> 注意 > 注意
为了简单起见,对于代码中可以设置访问级别的特性(属性、基本类型、函数等),在下面的章节中我们会称之为“实体”。 为了简单起见,对于代码中可以设置访问级别的特性(属性、基本类型、函数等),在下面的章节中我们会称之为“实体”。
<a name="modules_and_source_files"></a> <a name="modules_and_source_files"></a>
@ -51,7 +51,7 @@ Swift 中的访问控制模型基于模块和源文件这两个概念。
模块指的是独立的代码单元,框架或应用程序会作为一个独立的模块来构建和发布。在 Swift 中,一个模块可以使用 `import` 关键字导入另外一个模块。 模块指的是独立的代码单元,框架或应用程序会作为一个独立的模块来构建和发布。在 Swift 中,一个模块可以使用 `import` 关键字导入另外一个模块。
在 Swift 中Xcode 的每个 target例如框架或应用程序都被当作独立的模块处理。如果你是为了实现某个通用的功能或者是为了封装一些常用方法而将代码打包成独立的框架这个框架就是 Swift 中的一个模块。当它被导入到某个应用程序或者其他框架时,框架内容都将属于这个独立的模块。 在 Swift 中Xcode 的每个 target例如框架或应用程序都被当作独立的模块处理。如果你是为了实现某个通用的功能或者是为了封装一些常用方法而将代码打包成独立的框架这个框架就是 Swift 中的一个模块。当它被导入到某个应用程序或者其他框架时,框架内容都将属于这个独立的模块。
*源文件*就是 Swift 中的源代码文件,它通常属于一个模块,即一个应用程序或者框架。尽管我们一般会将不同的类型分别定义在不同的源文件中,但是同一个源文件也可以包含多个类型、函数之类的定义。 *源文件*就是 Swift 中的源代码文件,它通常属于一个模块,即一个应用程序或者框架。尽管我们一般会将不同的类型分别定义在不同的源文件中,但是同一个源文件也可以包含多个类型、函数之类的定义。
@ -142,7 +142,7 @@ var someInternalConstant = 0 // 隐式 internal
一个类型的访问级别也会影响到类型*成员*(属性、方法、构造器、下标)的默认访问级别。如果你将类型指定为 `private` 或者 `fileprivate` 级别,那么该类型的所有成员的默认访问级别也会变成 `private` 或者 `fileprivate` 级别。如果你将类型指定为公开或者 `internal` (或者不明确指定访问级别,而使用默认的 `internal` ),那么该类型的所有成员的默认访问级别将是内部访问。 一个类型的访问级别也会影响到类型*成员*(属性、方法、构造器、下标)的默认访问级别。如果你将类型指定为 `private` 或者 `fileprivate` 级别,那么该类型的所有成员的默认访问级别也会变成 `private` 或者 `fileprivate` 级别。如果你将类型指定为公开或者 `internal` (或者不明确指定访问级别,而使用默认的 `internal` ),那么该类型的所有成员的默认访问级别将是内部访问。
> 重要 > 重要
上面提到,一个 `public` 类型的所有成员的访问级别默认为 `internal` 级别,而不是 `public` 级别。如果你想将某个成员指定为 `public` 级别,那么你必须显式指定。这样做的好处是,在你定义公共接口的时候,可以明确地选择哪些接口是需要公开的,哪些是内部使用的,避免不小心将内部使用的接口公开。 上面提到,一个 `public` 类型的所有成员的访问级别默认为 `internal` 级别,而不是 `public` 级别。如果你想将某个成员指定为 `public` 级别,那么你必须显式指定。这样做的好处是,在你定义公共接口的时候,可以明确地选择哪些接口是需要公开的,哪些是内部使用的,避免不小心将内部使用的接口公开。
```swift ```swift
@ -174,7 +174,7 @@ private class SomePrivateClass { // 显式 private 类
元组的访问级别将由元组中访问级别最严格的类型来决定。例如,如果你构建了一个包含两种不同类型的元组,其中一个类型为 `internal`,另一个类型为 `private`,那么这个元组的访问级别为 `private` 元组的访问级别将由元组中访问级别最严格的类型来决定。例如,如果你构建了一个包含两种不同类型的元组,其中一个类型为 `internal`,另一个类型为 `private`,那么这个元组的访问级别为 `private`
> 注意 > 注意
元组不同于类、结构体、枚举、函数那样有单独的定义。元组的访问级别是在它被使用时自动推断出的,而无法明确指定。 元组不同于类、结构体、枚举、函数那样有单独的定义。元组的访问级别是在它被使用时自动推断出的,而无法明确指定。
<a name="function_types"></a> <a name="function_types"></a>
@ -266,7 +266,7 @@ internal class B: A {
<a name="constants_variables_properties_subscripts"></a> <a name="constants_variables_properties_subscripts"></a>
## 常量、变量、属性、下标 ## 常量、变量、属性、下标
常量、变量、属性不能拥有比它们的类型更高的访问级别。例如,你不能定义一个 `public` 级别的属性,但是它的类型却是 `private` 级别的。同样,下标也不能拥有比索引类型或返回类型更高的访问级别。 常量、变量、属性不能拥有比它们的类型更高的访问级别。例如,你不能定义一个 `public` 级别的属性,但是它的类型却是 `private` 级别的。同样,下标也不能拥有比索引类型或返回类型更高的访问级别。
如果常量、变量、属性、下标的类型是 `private` 级别的,那么它们必须明确指定访问级别为 `private` 如果常量、变量、属性、下标的类型是 `private` 级别的,那么它们必须明确指定访问级别为 `private`
@ -281,8 +281,8 @@ private var privateInstance = SomePrivateClass()
`Setter` 的访问级别可以低于对应的 `Getter` 的访问级别,这样就可以控制变量、属性或下标的读写权限。在 `var``subscript` 关键字之前,你可以通过 `fileprivate(set)``private(set)``internal(set)` 为它们的写入权限指定更低的访问级别。 `Setter` 的访问级别可以低于对应的 `Getter` 的访问级别,这样就可以控制变量、属性或下标的读写权限。在 `var``subscript` 关键字之前,你可以通过 `fileprivate(set)``private(set)``internal(set)` 为它们的写入权限指定更低的访问级别。
> 注意 > 注意
这个规则同时适用于存储型属性和计算型属性。即使你不明确指定存储型属性的 `Getter``Setter`Swift 也会隐式地为其创建 `Getter``Setter`,用于访问该属性的后备存储。使用 `fileprivate(set)``private(set)``internal(set)` 可以改变 `Setter` 的访问级别,这对计算型属性也同样适用。 这个规则同时适用于存储型属性和计算型属性。即使你不明确指定存储型属性的 `Getter``Setter`Swift 也会隐式地为其创建 `Getter``Setter`,用于访问该属性的后备存储。使用 `fileprivate(set)``private(set)``internal(set)` 可以改变 `Setter` 的访问级别,这对计算型属性也同样适用。
下面的例子中定义了一个名为 `TrackedString` 的结构体,它记录了 `value` 属性被修改的次数: 下面的例子中定义了一个名为 `TrackedString` 的结构体,它记录了 `value` 属性被修改的次数:
@ -299,7 +299,7 @@ struct TrackedString {
`TrackedString` 结构体定义了一个用于存储 `String` 值的属性 `value`,并将初始值设为 `""`(一个空字符串)。该结构体还定义了另一个用于存储 `Int` 值的属性 `numberOfEdits`,它用于记录属性 `value` 被修改的次数。这个功能通过属性 `value``didSet` 观察器实现,每当给 `value` 赋新值时就会调用 `didSet` 方法,然后将 `numberOfEdits` 的值加一。 `TrackedString` 结构体定义了一个用于存储 `String` 值的属性 `value`,并将初始值设为 `""`(一个空字符串)。该结构体还定义了另一个用于存储 `Int` 值的属性 `numberOfEdits`,它用于记录属性 `value` 被修改的次数。这个功能通过属性 `value``didSet` 观察器实现,每当给 `value` 赋新值时就会调用 `didSet` 方法,然后将 `numberOfEdits` 的值加一。
结构体 `TrackedString` 和它的属性 `value` 都没有显式地指定访问级别,所以它们都是用默认的访问级别 `internal`。但是该结构体的 `numberOfEdits` 属性使用了 `private(set)` 修饰符,这意味着 `numberOfEdits` 属性只能在结构体的定义中进行赋值。`numberOfEdits` 属性的 `Getter` 依然是默认的访问级别 `internal`,但是 `Setter` 的访问级别是 `private`,这表示该属性只能在内部修改,而在结构体的外部则表现为一个只读属性。 结构体 `TrackedString` 和它的属性 `value` 都没有显式地指定访问级别,所以它们都是用默认的访问级别 `internal`。但是该结构体的 `numberOfEdits` 属性使用了 `private(set)` 修饰符,这意味着 `numberOfEdits` 属性只能在结构体的定义中进行赋值。`numberOfEdits` 属性的 `Getter` 依然是默认的访问级别 `internal`,但是 `Setter` 的访问级别是 `private`,这表示该属性只能在内部修改,而在结构体的外部则表现为一个只读属性。
如果你实例化 `TrackedString` 结构体,并多次对 `value` 属性的值进行修改,你就会看到 `numberOfEdits` 的值会随着修改次数而变化: 如果你实例化 `TrackedString` 结构体,并多次对 `value` 属性的值进行修改,你就会看到 `numberOfEdits` 的值会随着修改次数而变化:
@ -356,7 +356,7 @@ public struct TrackedString {
协议中的每一个要求都具有和该协议相同的访问级别。你不能将协议中的要求设置为其他访问级别。这样才能确保该协议的所有要求对于任意采纳者都将可用。 协议中的每一个要求都具有和该协议相同的访问级别。你不能将协议中的要求设置为其他访问级别。这样才能确保该协议的所有要求对于任意采纳者都将可用。
> 注意 > 注意
如果你定义了一个 `public` 访问级别的协议,那么该协议的所有实现也会是 `public` 访问级别。这一点不同于其他类型,例如,当类型是 `public` 访问级别时,其成员的访问级别却只是 `internal` 如果你定义了一个 `public` 访问级别的协议,那么该协议的所有实现也会是 `public` 访问级别。这一点不同于其他类型,例如,当类型是 `public` 访问级别时,其成员的访问级别却只是 `internal`
<a name="protocol_inheritance"></a> <a name="protocol_inheritance"></a>
@ -373,7 +373,7 @@ public struct TrackedString {
如果你采纳了协议,那么实现了协议的所有要求后,你必须确保这些实现的访问级别不能低于协议的访问级别。例如,一个 `public` 级别的类型,采纳了 `internal` 级别的协议,那么协议的实现至少也得是 `internal` 级别。 如果你采纳了协议,那么实现了协议的所有要求后,你必须确保这些实现的访问级别不能低于协议的访问级别。例如,一个 `public` 级别的类型,采纳了 `internal` 级别的协议,那么协议的实现至少也得是 `internal` 级别。
> 注意 > 注意
Swift 和 Objective-C 一样,协议的一致性是全局的,也就是说,在同一程序中,一个类型不可能用两种不同的方式实现同一个协议。 Swift 和 Objective-C 一样,协议的一致性是全局的,也就是说,在同一程序中,一个类型不可能用两种不同的方式实现同一个协议。
<a name="extensions"></a> <a name="extensions"></a>
@ -426,5 +426,5 @@ extension SomeStruct: SomeProtocol {
你定义的任何类型别名都会被当作不同的类型,以便于进行访问控制。类型别名的访问级别不可高于其表示的类型的访问级别。例如,`private` 级别的类型别名可以作为 `private``file-private``internal``public`或者`open`类型的别名,但是 `public` 级别的类型别名只能作为 `public` 类型的别名,不能作为 `internal``file-private`,或 `private` 类型的别名。 你定义的任何类型别名都会被当作不同的类型,以便于进行访问控制。类型别名的访问级别不可高于其表示的类型的访问级别。例如,`private` 级别的类型别名可以作为 `private``file-private``internal``public`或者`open`类型的别名,但是 `public` 级别的类型别名只能作为 `public` 类型的别名,不能作为 `internal``file-private`,或 `private` 类型的别名。
> 注意 > 注意
这条规则也适用于为满足协议一致性而将类型别名用于关联类型的情况。 这条规则也适用于为满足协议一致性而将类型别名用于关联类型的情况。

View File

@ -15,7 +15,7 @@
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-17 > 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-17
> >
> 3.0 > 3.0
> 翻译+校对:[mmoaay](https://github.com/mmoaay) 2016-09-20 > 翻译+校对:[mmoaay](https://github.com/mmoaay) 2016-09-20
> 3.0.1shanks2016-11-13 > 3.0.1shanks2016-11-13
本页内容包括: 本页内容包括:
@ -307,7 +307,7 @@ signedOverflow = signedOverflow &- 1
如果想查看完整的 Swift 运算符优先级和结合性规则,请参考[表达式](../chapter3/04_Expressions.html)。如果想查看 Swift 标准库提供所有的运算符,请查看 [Swift Standard Library Operators Reference](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.html#//apple_ref/doc/uid/TP40016054)。 如果想查看完整的 Swift 运算符优先级和结合性规则,请参考[表达式](../chapter3/04_Expressions.html)。如果想查看 Swift 标准库提供所有的运算符,请查看 [Swift Standard Library Operators Reference](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.html#//apple_ref/doc/uid/TP40016054)。
> 注意 > 注意
> 相对 C 语言和 Objective-C 来说Swift 的运算符优先级和结合性规则更加简洁和可预测。但是,这也意味着它们相较于 C 语言及其衍生语言并不是完全一致的。在对现有的代码进行移植的时候,要注意确保运算符的行为仍然符合你的预期。 > 相对 C 语言和 Objective-C 来说Swift 的运算符优先级和结合性规则更加简洁和可预测。但是,这也意味着它们相较于 C 语言及其衍生语言并不是完全一致的。在对现有的代码进行移植的时候,要注意确保运算符的行为仍然符合你的预期。
<a name="operator_functions"></a> <a name="operator_functions"></a>
@ -396,7 +396,7 @@ original += vectorToAdd
// original 的值现在为 (4.0, 6.0) // original 的值现在为 (4.0, 6.0)
``` ```
> 注意 > 注意
> 不能对默认的赋值运算符(`=`)进行重载。只有组合赋值运算符可以被重载。同样地,也无法对三目条件运算符 `a ? b : c` 进行重载。 > 不能对默认的赋值运算符(`=`)进行重载。只有组合赋值运算符可以被重载。同样地,也无法对三目条件运算符 `a ? b : c` 进行重载。
<a name="equivalence_operators"></a> <a name="equivalence_operators"></a>
@ -481,5 +481,5 @@ let plusMinusVector = firstVector +- secondVector
这个运算符把两个向量的 `x` 值相加,同时用第一个向量的 `y` 值减去第二个向量的 `y` 值。因为它本质上是属于“相加型”运算符,所以将它放置 `+``-` 等默认的中缀“相加型”运算符相同的优先级组中。关于 Swift 标准库提供的运算符,以及完整的运算符优先级组和结合性设置,请参考 [Swift Standard Library Operators Reference](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.html#//apple_ref/doc/uid/TP40016054)。而更多关于优先级组以及自定义操作符和优先级组的语法,请参考[运算符声明](#operator_declaration) 这个运算符把两个向量的 `x` 值相加,同时用第一个向量的 `y` 值减去第二个向量的 `y` 值。因为它本质上是属于“相加型”运算符,所以将它放置 `+``-` 等默认的中缀“相加型”运算符相同的优先级组中。关于 Swift 标准库提供的运算符,以及完整的运算符优先级组和结合性设置,请参考 [Swift Standard Library Operators Reference](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.html#//apple_ref/doc/uid/TP40016054)。而更多关于优先级组以及自定义操作符和优先级组的语法,请参考[运算符声明](#operator_declaration)
> 注意 > 注意
> 当定义前缀与后缀运算符的时候,我们并没有指定优先级。然而,如果对同一个值同时使用前缀与后缀运算符,则后缀运算符会先参与运算。 > 当定义前缀与后缀运算符的时候,我们并没有指定优先级。然而,如果对同一个值同时使用前缀与后缀运算符,则后缀运算符会先参与运算。