翻译细节与 markdown 统一格式修改 (#779)
* 修正全角逗号、句号的使用 * 修正逗号使用 * 修正一处代码空格错误 * 修正斜体范围,引用的空格使用 * 修正示例代码错误 * 修正标点,修正示例代码 * 修正标点 * 修正标点 * 添加 Swift 3.1 的更新 * 修改 Swift 3.0.1 位置 * 添加 Swift 4.0.3 更新 * 添加 Swift 4.1 更新 * 修正示例代码 * 修正 markdown 引用语法,优化翻译语句 * 修正示例代码 * 修正标点使用,优化翻译语句 * 修正示例代码 * 修正示例代码 * 优化翻译语句,修正示例代码语法 * 更新示例代码以符合 Swift 4.1 * 优化 markdown 引用格式的使用 * 优化 markdown 行内代码块使用,代码块与正文使用空格分隔 * 人工校验 markdown 行内代码块使用 * 中英文空格分隔 * 移除行末空格 * 人工校验 markdown 行内代码块使用 * 修正 markdown 无序列表使用
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
> 2016.9.23: 已经更新到 Swift 3.0。
|
> 2016.9.23: 已经更新到 Swift 3.0。
|
||||||
# 3.0 更新说明
|
# 3.0 更新说明
|
||||||
Swift 3.0 是自 Swift 开源以来第一个大的版本更新。从语言角度不兼容之前的 Swift 2.2 和 Swift 2.3 版本。Swift 3.0 的更新说明,大家可以查看[官方blog的说明](https://swift.org/blog/swift-3-0-released/),也可以关注 [SwiftGG](http://swift.gg) 最新的文章。学习官方文档,是掌握语言特性点的最佳途径,感谢翻译的小伙伴们为 Swift 社区所做贡献!
|
Swift 3.0 是自 Swift 开源以来第一个大的版本更新。从语言角度不兼容之前的 Swift 2.2 和 Swift 2.3 版本。Swift 3.0 的更新说明,大家可以查看[官方 blog 的说明](https://swift.org/blog/swift-3-0-released/),也可以关注 [SwiftGG](http://swift.gg) 最新的文章。学习官方文档,是掌握语言特性点的最佳途径,感谢翻译的小伙伴们为 Swift 社区所做贡献!
|
||||||
|
|
||||||
# 3.0 译者记录
|
# 3.0 译者记录
|
||||||
相关[issue](https://github.com/numbbbbb/the-swift-programming-language-in-chinese/issues/628)
|
相关[issue](https://github.com/numbbbbb/the-swift-programming-language-in-chinese/issues/628)
|
||||||
|
|||||||
@ -45,11 +45,11 @@
|
|||||||
* [泛型参数](chapter3/09_Generic_Parameters_and_Arguments.md)
|
* [泛型参数](chapter3/09_Generic_Parameters_and_Arguments.md)
|
||||||
* [语法总结](chapter3/10_Summary_of_the_Grammar.md)
|
* [语法总结](chapter3/10_Summary_of_the_Grammar.md)
|
||||||
|
|
||||||
* 苹果官方Blog官方翻译
|
* 苹果官方 Blog 官方翻译
|
||||||
* [Access Control 权限控制的黑与白](chapter4/01_Access_Control.md)
|
* [Access Control 权限控制的黑与白](chapter4/01_Access_Control.md)
|
||||||
* [造个类型不是梦-白话Swift类型创建](chapter4/02_Type_Custom.md)
|
* [造个类型不是梦-白话 Swift 类型创建](chapter4/02_Type_Custom.md)
|
||||||
* [WWDC里面的那个“大炮打气球”](chapter4/03_Ballons.md)
|
* [WWDC 里面的那个“大炮打气球”](chapter4/03_Ballons.md)
|
||||||
* [Swift与C语言指针友好合作](chapter4/04_Interacting_with_C_Pointers.md)
|
* [Swift 与 C 语言指针友好合作](chapter4/04_Interacting_with_C_Pointers.md)
|
||||||
* [引用类型和值类型的恩怨](chapter4/05_Value_and_Reference_Types.md)
|
* [引用类型和值类型的恩怨](chapter4/05_Value_and_Reference_Types.md)
|
||||||
* [访问控制和Protected](chapter4/06_Access_Control_and_Protected.md)
|
* [访问控制和 Protected](chapter4/06_Access_Control_and_Protected.md)
|
||||||
* [可选类型完美解决占位问题](chapter4/07_Optional_Case_Study.md)
|
* [可选类型完美解决占位问题](chapter4/07_Optional_Case_Study.md)
|
||||||
@ -8,10 +8,14 @@
|
|||||||
> 2.0
|
> 2.0
|
||||||
> 翻译+校对:[xtymichael](https://github.com/xtymichael)
|
> 翻译+校对:[xtymichael](https://github.com/xtymichael)
|
||||||
|
|
||||||
> 3.0 翻译+校对:[shanks](http://codebuild.me),2016-10-06
|
> 3.0
|
||||||
> 3.0.1 review : 2016-11-09
|
> 翻译+校对:[shanks](http://codebuild.me),2016-10-06
|
||||||
|
|
||||||
> 3.1 校对: [SketchK](https://github.com/SketchK) 2017-04-08
|
> 3.0.1
|
||||||
|
> review : 2016-11-09
|
||||||
|
|
||||||
|
> 3.1
|
||||||
|
> 校对: [SketchK](https://github.com/SketchK) 2017-04-08
|
||||||
|
|
||||||
> 4.0
|
> 4.0
|
||||||
> 翻译:[rain2540](https://github.com/rain2540) 2017-09-21
|
> 翻译:[rain2540](https://github.com/rain2540) 2017-09-21
|
||||||
@ -23,7 +27,7 @@ Swift 是一种非常好的编写软件的方式,无论是手机,台式机
|
|||||||
|
|
||||||
Swift 对于初学者来说也很友好。它是第一个既满足工业标准又像脚本语言一样充满表现力和趣味的系统编程语言。它支持代码预览(playgrounds),这个革命性的特性可以允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。
|
Swift 对于初学者来说也很友好。它是第一个既满足工业标准又像脚本语言一样充满表现力和趣味的系统编程语言。它支持代码预览(playgrounds),这个革命性的特性可以允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。
|
||||||
|
|
||||||
Swift通过采用现代编程模式来避免大量常见编程错误:
|
Swift 通过采用现代编程模式来避免大量常见编程错误:
|
||||||
|
|
||||||
* 变量始终在使用前初始化。
|
* 变量始终在使用前初始化。
|
||||||
* 检查数组索引超出范围的错误。
|
* 检查数组索引超出范围的错误。
|
||||||
|
|||||||
@ -10,13 +10,15 @@
|
|||||||
> 翻译+校对:[xtymichael](https://github.com/xtymichael)
|
> 翻译+校对:[xtymichael](https://github.com/xtymichael)
|
||||||
|
|
||||||
> 2.2
|
> 2.2
|
||||||
> 翻译:[175](https://github.com/Brian175),2016-04-09 校对:[SketchK](https://github.com/SketchK),2016-05-11
|
> 翻译:[175](https://github.com/Brian175),2016-04-09
|
||||||
>
|
> 校对:[SketchK](https://github.com/SketchK),2016-05-11
|
||||||
|
|
||||||
> 3.0
|
> 3.0
|
||||||
> 翻译+校对:[shanks](http://codebuild.me),2016-10-06
|
> 翻译+校对:[shanks](http://codebuild.me),2016-10-06
|
||||||
|
|
||||||
> 3.0.1 review: 2016-11-09
|
> 3.0.1
|
||||||
>
|
> review: 2016-11-09
|
||||||
|
|
||||||
> 3.1 校对: [SketchK](https://github.com/SketchK) 2017-04-08
|
> 3.1 校对: [SketchK](https://github.com/SketchK) 2017-04-08
|
||||||
|
|
||||||
> 4.0
|
> 4.0
|
||||||
@ -27,14 +29,14 @@
|
|||||||
|
|
||||||
本页内容包括:
|
本页内容包括:
|
||||||
|
|
||||||
- [简单值(Simple Values)](#simple_values)
|
- [简单值(Simple Values)](#simple_values)
|
||||||
- [控制流(Control Flow)](#control_flow)
|
- [控制流(Control Flow)](#control_flow)
|
||||||
- [函数和闭包(Functions and Closures)](#functions_and_closures)
|
- [函数和闭包(Functions and Closures)](#functions_and_closures)
|
||||||
- [对象和类(Objects and Classes)](#objects_and_classes)
|
- [对象和类(Objects and Classes)](#objects_and_classes)
|
||||||
- [枚举和结构体(Enumerations and Structures)](#enumerations_and_structures)
|
- [枚举和结构体(Enumerations and Structures)](#enumerations_and_structures)
|
||||||
- [协议和扩展(Protocols and Extensions)](#protocols_and_extensions)
|
- [协议和扩展(Protocols and Extensions)](#protocols_and_extensions)
|
||||||
- [错误处理(Error Handling)](#error_handling)
|
- [错误处理(Error Handling)](#error_handling)
|
||||||
- [泛型(Generics)](#generics)
|
- [泛型(Generics)](#generics)
|
||||||
|
|
||||||
通常来说,编程语言教程中的第一个程序应该在屏幕上打印 “Hello, world”。在 Swift 中,可以用一行代码实现:
|
通常来说,编程语言教程中的第一个程序应该在屏幕上打印 “Hello, world”。在 Swift 中,可以用一行代码实现:
|
||||||
|
|
||||||
@ -48,7 +50,7 @@ print("Hello, world!")
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 最好的体验是把这一章作为Playground文件在Xcode中打开。 Playgrounds允许你可以编辑代码并立刻看到输出结果。
|
> 最好的体验是把这一章作为 Playground 文件在 Xcode 中打开。 Playgrounds 允许你可以编辑代码并立刻看到输出结果。
|
||||||
>
|
>
|
||||||
> [Download Playground](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.playground.zip)
|
> [Download Playground](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.playground.zip)
|
||||||
|
|
||||||
@ -140,7 +142,7 @@ occupations = [:]
|
|||||||
<a name="control_flow"></a>
|
<a name="control_flow"></a>
|
||||||
## 控制流
|
## 控制流
|
||||||
|
|
||||||
使用 `if` 和 `switch` 来进行条件操作,使用 `for-in`、 `while` 和 `repeat-while` 来进行循环。包裹条件和循环变量的括号可以省略,但是语句体的大括号是必须的。
|
使用 `if` 和 `switch` 来进行条件操作,使用 `for-in`、`while` 和 `repeat-while` 来进行循环。包裹条件和循环变量的括号可以省略,但是语句体的大括号是必须的。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let individualScores = [75, 43, 103, 87, 12]
|
let individualScores = [75, 43, 103, 87, 12]
|
||||||
@ -157,7 +159,7 @@ print(teamScore)
|
|||||||
|
|
||||||
在 `if` 语句中,条件必须是一个布尔表达式——这意味着像 `if score { ... }` 这样的代码将报错,而不会隐形地与 0 做对比。
|
在 `if` 语句中,条件必须是一个布尔表达式——这意味着像 `if score { ... }` 这样的代码将报错,而不会隐形地与 0 做对比。
|
||||||
|
|
||||||
你可以一起使用 `if` 和 `let` 一起来处理值缺失的情况。这些值可由可选值来代表。一个可选的值是一个具体的值或者是 `nil` 以表示值缺失。在类型后面加一个问号(`?ß`)来标记这个变量的值是可选的。
|
你可以一起使用 `if` 和 `let` 一起来处理值缺失的情况。这些值可由可选值来代表。一个可选的值是一个具体的值或者是 `nil` 以表示值缺失。在类型后面加一个问号(`?`)来标记这个变量的值是可选的。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var optionalString: String? = "Hello"
|
var optionalString: String? = "Hello"
|
||||||
@ -713,7 +715,7 @@ print(protocolValue.simpleDescription)
|
|||||||
// print(protocolValue.anotherProperty) // 去掉注释可以看到错误
|
// print(protocolValue.anotherProperty) // 去掉注释可以看到错误
|
||||||
```
|
```
|
||||||
|
|
||||||
即使 `protocolValue` 变量运行时的类型是 `simpleClass` ,编译器还是会把它的类型当做`ExampleProtocol`。这表示你不能调用在协议之外的方法或者属性。
|
即使 `protocolValue` 变量运行时的类型是 `simpleClass` ,编译器还是会把它的类型当做 `ExampleProtocol`。这表示你不能调用在协议之外的方法或者属性。
|
||||||
|
|
||||||
<a name="error_handling"></a>
|
<a name="error_handling"></a>
|
||||||
## 错误处理
|
## 错误处理
|
||||||
|
|||||||
@ -187,10 +187,10 @@
|
|||||||
更新<a href="https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID48">自动引用计数</a>章节中关于 weak 和 unowned 引用的讨论。
|
更新<a href="https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID48">自动引用计数</a>章节中关于 weak 和 unowned 引用的讨论。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
增加<a href="https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID381">声明标识符</a>章节中关于新的标识符`unowned`,`unowend(safe)`和`unowned(unsafe)`的描述。
|
增加<a href="https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID381">声明标识符</a>章节中关于新的标识符 `unowned`,`unowend(safe)` 和 `unowned(unsafe)` 的描述。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
增加<a href="https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html#//apple_ref/doc/uid/TP40014097-CH22-ID342">Any 和 AnyObject 的类型转换</a>一节中关于使用类型`Any`作为可选值的描述。
|
增加<a href="https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html#//apple_ref/doc/uid/TP40014097-CH22-ID342">Any 和 AnyObject 的类型转换</a>一节中关于使用类型 `Any` 作为可选值的描述。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
更新<a href="https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID383">表达式</a>章节,把括号表达式和元组表达式的描述分开。
|
更新<a href="https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID383">表达式</a>章节,把括号表达式和元组表达式的描述分开。
|
||||||
@ -450,11 +450,11 @@
|
|||||||
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID145">枚举</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID536">递归枚举</a>一节和<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID351">声明</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID365">任意类型用例的枚举</a>一节中关于递归枚举的内容。
|
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID145">枚举</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID536">递归枚举</a>一节和<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID351">声明</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID365">任意类型用例的枚举</a>一节中关于递归枚举的内容。
|
||||||
</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-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>
|
||||||
<li>
|
<li>
|
||||||
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID267">协议</a>一章中<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID521">协议扩展</a>一节中关于协议扩展的内容。
|
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID267">协议</a>一章中<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID521">协议扩展</a>一节中关于协议扩展的内容。
|
||||||
@ -577,7 +577,7 @@
|
|||||||
更新至 Swift 1.2。
|
更新至 Swift 1.2。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Swift现在自身提供了一个<code>Set</code>集合类型,更多信息请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-ID484">集合</a>
|
Swift 现在自身提供了一个<code>Set</code>集合类型,更多信息请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-ID484">集合</a>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@ -587,7 +587,7 @@
|
|||||||
对于类型属性和方法现在可以使用<code>static</code>关键字作为声明描述符,更多信息,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID483">类型变量属性</a>
|
对于类型属性和方法现在可以使用<code>static</code>关键字作为声明描述符,更多信息,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID483">类型变量属性</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Swift现在包含一个<code>as?</code>和<code>as!</code>的向下可失败类型转换运算符。更多信息,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID283">协议遵循性检查</a>
|
Swift 现在包含一个<code>as?</code>和<code>as!</code>的向下可失败类型转换运算符。更多信息,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID283">协议遵循性检查</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
增加了一个新的指导章节,它是关于<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID495">字符串索引</a>的
|
增加了一个新的指导章节,它是关于<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID495">字符串索引</a>的
|
||||||
@ -599,7 +599,7 @@
|
|||||||
更新了常量和常量属性在声明和构造时的规则,更多信息,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID355">常量声明</a>
|
更新了常量和常量属性在声明和构造时的规则,更多信息,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID355">常量声明</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
更新了字符串字面量中Unicode标量集的定义,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID295">字符串字面量中的特殊字符</a>
|
更新了字符串字面量中 Unicode 标量集的定义,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID295">字符串字面量中的特殊字符</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
更新了<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-ID73">区间运算符</a>章节来提示当半开区间运算符含有相同的起止索引时,其区间为空。
|
更新了<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-ID73">区间运算符</a>章节来提示当半开区间运算符含有相同的起止索引时,其区间为空。
|
||||||
@ -617,7 +617,7 @@
|
|||||||
更新了<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID58">捕获列表</a>章节来澄清对于闭包捕获列表中的弱引用和无主引用的使用语法。
|
更新了<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID58">捕获列表</a>章节来澄清对于闭包捕获列表中的弱引用和无主引用的使用语法。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
更新了<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID418">运算符</a>章节来明确指明一些例子来说明自定义运算符所支持的特性,如数学运算符,各种符号,Unicode符号块等
|
更新了<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID418">运算符</a>章节来明确指明一些例子来说明自定义运算符所支持的特性,如数学运算符,各种符号,Unicode 符号块等
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
在函数作用域中的常量声明时可以不被初始化,它必须在第一次使用前被赋值。更多的信息,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID355">常量声明</a>
|
在函数作用域中的常量声明时可以不被初始化,它必须在第一次使用前被赋值。更多的信息,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID355">常量声明</a>
|
||||||
@ -673,7 +673,7 @@
|
|||||||
带有原始值的枚举类型增加了一个<code>rawValue</code>属性替代<code>toRaw()</code>方法,同时使用了一个以<code>rawValue</code>为参数的失败构造器来替代<code>fromRaw()</code>方法。更多的信息,请看<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html">原始值(Raw Values)</a>和<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html">带原始值的枚举类型(Enumerations with Cases of a Raw-Value Type)</a>部分。
|
带有原始值的枚举类型增加了一个<code>rawValue</code>属性替代<code>toRaw()</code>方法,同时使用了一个以<code>rawValue</code>为参数的失败构造器来替代<code>fromRaw()</code>方法。更多的信息,请看<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html">原始值(Raw Values)</a>和<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html">带原始值的枚举类型(Enumerations with Cases of a Raw-Value Type)</a>部分。
|
||||||
</li>
|
</li>
|
||||||
<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>
|
||||||
@ -697,7 +697,7 @@
|
|||||||
<td scope="row">2014-08-18</td>
|
<td scope="row">2014-08-18</td>
|
||||||
<td><ul class="list-bullet">
|
<td><ul class="list-bullet">
|
||||||
<li>
|
<li>
|
||||||
发布新的文档用以详述 Swift 1.0,苹果公司针对iOS和OS X应用的全新开发语言。
|
发布新的文档用以详述 Swift 1.0,苹果公司针对 iOS 和 OS X 应用的全新开发语言。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
在章节协议中,增加新的小节:<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_397">对构造器的规定(Initializer Requirements)</a>
|
在章节协议中,增加新的小节:<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_397">对构造器的规定(Initializer Requirements)</a>
|
||||||
@ -715,10 +715,10 @@
|
|||||||
在<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Attributes.html#//apple_ref/doc/uid/TP40014097-CH35-XID_516">声明特性(Declaration Attributes)</a>章节增加了关于<code>availability</code>特性的一些信息
|
在<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Attributes.html#//apple_ref/doc/uid/TP40014097-CH35-XID_516">声明特性(Declaration Attributes)</a>章节增加了关于<code>availability</code>特性的一些信息
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_478">可选类型(Optionals)</a> 若有值时,不再隐式的转换为 <code>true</code>,同样,若无值时,也不再隐式的转换为 <code>false</code>,这是为了避免在判别 optional <code>Bool</code> 的值时产生困惑。 替代的方案是,用<code>==</code> 或 <code>!=</code> 运算符显式地去判断Optinal是否是 <code>nil</code>,以确认其是否包含值。
|
<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_478">可选类型(Optionals)</a> 若有值时,不再隐式的转换为 <code>true</code>,同样,若无值时,也不再隐式的转换为 <code>false</code>,这是为了避免在判别 optional <code>Bool</code> 的值时产生困惑。 替代的方案是,用<code>==</code> 或 <code>!=</code> 运算符显式地去判断 Optinal 是否是 <code>nil</code>,以确认其是否包含值。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Swift新增了一个 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-XID_124" data-id="//apple_ref/doc/uid/TP40014097-CH6-XID_124">Nil合并运算符(Nil Coalescing Operator)</a> (<code>a ?? b</code>), 该表达式中,如果Optional <code>a</code>的值存在,则取得它并返回,若Optional <code>a</code>为<code>nil</code>,则返回默认值 <code>b</code>
|
Swift 新增了一个 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-XID_124" data-id="//apple_ref/doc/uid/TP40014097-CH6-XID_124">Nil 合并运算符(Nil Coalescing Operator)</a> (<code>a ?? b</code>), 该表达式中,如果 Optional <code>a</code>的值存在,则取得它并返回,若 Optional <code>a</code>为<code>nil</code>,则返回默认值 <code>b</code>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
更新和扩展 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_434">字符串的比较(Comparing Strings)</a> 章节,用以反映和展示'字符串和字符的比较',以及'前缀(prefix)/后缀(postfix)比较'都开始基于扩展字符集(extended grapheme clusters)规范的等价比较。
|
更新和扩展 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_434">字符串的比较(Comparing Strings)</a> 章节,用以反映和展示'字符串和字符的比较',以及'前缀(prefix)/后缀(postfix)比较'都开始基于扩展字符集(extended grapheme clusters)规范的等价比较。
|
||||||
@ -736,13 +736,13 @@
|
|||||||
添加了一个提示:在 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-XID_126">范围运算符(Range Operators)</a>中,比如, <code>a...b</code> 和 <code>a..<b</code> ,起始值<code>a</code>不能大于结束值<code>b</code>.
|
添加了一个提示:在 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-XID_126">范围运算符(Range Operators)</a>中,比如, <code>a...b</code> 和 <code>a..<b</code> ,起始值<code>a</code>不能大于结束值<code>b</code>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
重写了<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_293">继承(Inheritance)</a> 这一章:删除了本章中关于构造器重写的介绍性报道;转而将更多的注意力放到新增的部分——子类的新功能,以及如何通过重写(overrides)修改已有的功能。另外,小节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_301">重写属性的Getters和Setters(Overriding Property Getters and Setters)</a> 中的例子已经被替换为展示如何重写一个 <code>description</code> 属性。 (而关于如何在子类的构造器中修改继承属性的默认值的例子,已经被移到 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_293">构造过程(Initialization)</a> 这一章。)
|
重写了<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_293">继承(Inheritance)</a> 这一章:删除了本章中关于构造器重写的介绍性报道;转而将更多的注意力放到新增的部分——子类的新功能,以及如何通过重写(overrides)修改已有的功能。另外,小节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_301">重写属性的 Getters 和 Setters(Overriding Property Getters and Setters)</a> 中的例子已经被替换为展示如何重写一个 <code>description</code> 属性。 (而关于如何在子类的构造器中修改继承属性的默认值的例子,已经被移到 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_293">构造过程(Initialization)</a> 这一章。)
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
更新了 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_331">构造器的继承与重写(Initializer Inheritance and Overriding)</a> 小节以标示: 重写一个特定的构造器必须使用 <code>override</code> 修饰符。
|
更新了 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_331">构造器的继承与重写(Initializer Inheritance and Overriding)</a> 小节以标示: 重写一个特定的构造器必须使用 <code>override</code> 修饰符。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
更新 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_339"> Required构造器(Required Initializers)</a> 小节以标示:<code>required</code> 修饰符现在需要出现在所有子类的required构造器的声明中,而required构造器的实现,现在可以仅从父类自动继承。
|
更新 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_339"> Required 构造器(Required Initializers)</a> 小节以标示:<code>required</code> 修饰符现在需要出现在所有子类的 required 构造器的声明中,而 required 构造器的实现,现在可以仅从父类自动继承。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
中置(Infix)的 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_80">运算符函数(Operator Functions)</a> 不再需要<code>@infix</code> 属性。
|
中置(Infix)的 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_80">运算符函数(Operator Functions)</a> 不再需要<code>@infix</code> 属性。
|
||||||
@ -751,7 +751,7 @@
|
|||||||
<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/RevisionHistory.html#//apple_ref/doc/uid/TP40014097-CH40-XID_1631">前置和后置运算符(Prefix and Postfix Operators)</a>的<code>@prefix</code> 和 <code>@postfix</code> 属性,已变更为 <code>prefix</code> 和 <code>postfix</code> 声明修饰符(declaration modifiers)。
|
<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/RevisionHistory.html#//apple_ref/doc/uid/TP40014097-CH40-XID_1631">前置和后置运算符(Prefix and Postfix Operators)</a>的<code>@prefix</code> 和 <code>@postfix</code> 属性,已变更为 <code>prefix</code> 和 <code>postfix</code> 声明修饰符(declaration modifiers)。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
增加一条注解:当Prefix和postfix运算符被作用于同一个操作数时,关于<a href="AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_81" data-id="//apple_ref/doc/uid/TP40014097-CH27-XID_81">前置和后置运算符(Prefix and Postfix Operators)</a>的顺序(postfix运算符会先被执行)
|
增加一条注解:当 Prefix 和 postfix 运算符被作用于同一个操作数时,关于<a href="AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_81" data-id="//apple_ref/doc/uid/TP40014097-CH27-XID_81">前置和后置运算符(Prefix and Postfix Operators)</a>的顺序(postfix 运算符会先被执行)
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
在运算符函数(Operator functions)中, <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_82" data-id="//apple_ref/doc/uid/TP40014097-CH27-XID_82">组合赋值运算符(Compound Assignment Operators)</a> 不再使用 <code>@assignment</code> 属性来定义函数。
|
在运算符函数(Operator functions)中, <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_82" data-id="//apple_ref/doc/uid/TP40014097-CH27-XID_82">组合赋值运算符(Compound Assignment Operators)</a> 不再使用 <code>@assignment</code> 属性来定义函数。
|
||||||
@ -763,7 +763,7 @@
|
|||||||
增加信息:关于<code>dynamic</code> 声明修饰符(declaration modifier),于章节 <a href="Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_705" data-id="//apple_ref/doc/uid/TP40014097-CH34-XID_705">声明修饰符(Declaration Modifiers)</a>.
|
增加信息:关于<code>dynamic</code> 声明修饰符(declaration modifier),于章节 <a href="Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_705" data-id="//apple_ref/doc/uid/TP40014097-CH34-XID_705">声明修饰符(Declaration Modifiers)</a>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
增加信息:<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_886">字面量Literals</a> 的类型推导(type inference)
|
增加信息:<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_886">字面量 Literals</a> 的类型推导(type inference)
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
为章节<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_597">Curried Functions</a>添加了更多的信息。
|
为章节<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_597">Curried Functions</a>添加了更多的信息。
|
||||||
@ -772,22 +772,22 @@
|
|||||||
加入新的章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html#//apple_ref/doc/uid/TP40014097-CH41-XID_29">权限控制(Access Control)</a>.
|
加入新的章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html#//apple_ref/doc/uid/TP40014097-CH41-XID_29">权限控制(Access Control)</a>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
更新了章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_413">字符串和字符(Strings and Characters)</a> 用以表明,在Swift中,<code>Character</code> 类型现在代表的是扩展字符集(extended grapheme cluster)中的一个Unicode,为此,新增了小节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_431">Extended Grapheme Clusters</a> 。同时,为小节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_428">Unicode标量(Unicode Scalars)</a> 和 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_434">字符串比较(Comparing Strings)</a>增加了更多内容。
|
更新了章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_413">字符串和字符(Strings and Characters)</a> 用以表明,在 Swift 中,<code>Character</code> 类型现在代表的是扩展字符集(extended grapheme cluster)中的一个 Unicode,为此,新增了小节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_431">Extended Grapheme Clusters</a> 。同时,为小节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_428">Unicode 标量(Unicode Scalars)</a> 和 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_434">字符串比较(Comparing Strings)</a>增加了更多内容。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
更新章节<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_856">字符串字面量(String Literals)</a>:在一个字符串中,Unicode标量(Unicode scalars) 以 <code>\u{n}</code>的形式来表示,<code>n</code> 是一个最大可以有8位的16进制数(hexadecimal digits)
|
更新章节<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_856">字符串字面量(String Literals)</a>:在一个字符串中,Unicode 标量(Unicode scalars) 以 <code>\u{n}</code>的形式来表示,<code>n</code> 是一个最大可以有8位的16进制数(hexadecimal digits)
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<code>NSString</code> <code>length</code> 属性已被映射到Swift的内建 <code>String</code>类型。(注意,这两属性的类型是<code>utf16Count</code>,而非 <code>utf16count</code>)。
|
<code>NSString</code> <code>length</code> 属性已被映射到 Swift 的内建 <code>String</code>类型。(注意,这两属性的类型是<code>utf16Count</code>,而非 <code>utf16count</code>)。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Swift的内建 <code>String</code> 类型不再拥有 <code>uppercaseString</code> 和 <code>lowercaseString</code> 属性。其对应部分在章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_413">字符串和字符(Strings and Characters)</a>已经被删除,并且各种对应的代码用例也已被更新。
|
Swift 的内建 <code>String</code> 类型不再拥有 <code>uppercaseString</code> 和 <code>lowercaseString</code> 属性。其对应部分在章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_413">字符串和字符(Strings and Characters)</a>已经被删除,并且各种对应的代码用例也已被更新。
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
加入新的章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_315">没有外部名的构造器参数(Initializer Parameters Without External Names)</a>.
|
加入新的章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_315">没有外部名的构造器参数(Initializer Parameters Without External Names)</a>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
加入新的章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_339"> Required构造器(Required Initializers)</a>.
|
加入新的章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_339"> Required 构造器(Required Initializers)</a>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
加入新的章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html#//apple_ref/doc/uid/TP40014097-CH10-XID_252">可选元祖(函数)返回类型 (Optional Tuple Return Types)</a>.
|
加入新的章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html#//apple_ref/doc/uid/TP40014097-CH10-XID_252">可选元祖(函数)返回类型 (Optional Tuple Return Types)</a>.
|
||||||
@ -802,7 +802,7 @@
|
|||||||
更新整本书 —— 引用 <code>..<</code> 作为<a href="BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-XID_128" data-id="//apple_ref/doc/uid/TP40014097-CH6-XID_128">区间运算符(Half-Open Range Operator)</a> (取代原先的<code>..</code> ).
|
更新整本书 —— 引用 <code>..<</code> 作为<a href="BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-XID_128" data-id="//apple_ref/doc/uid/TP40014097-CH6-XID_128">区间运算符(Half-Open Range Operator)</a> (取代原先的<code>..</code> ).
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
更新了小节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-XID_185">读取和修改字典(Accessing and Modifying a Dictionary)</a>: <code>Dictionary</code> 现在早呢更加了一个 Boolean型的属性: <code>isEmpty</code>
|
更新了小节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-XID_185">读取和修改字典(Accessing and Modifying a Dictionary)</a>: <code>Dictionary</code> 现在早呢更加了一个 Boolean 型的属性: <code>isEmpty</code>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
解释了哪些字符(集)可被用来定义<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_85">自定义操作符 (Custom Operators)</a>
|
解释了哪些字符(集)可被用来定义<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_85">自定义操作符 (Custom Operators)</a>
|
||||||
@ -811,7 +811,7 @@
|
|||||||
<code>nil</code> 和布尔运算中的 <code>true</code> 和 <code>false</code> 现在被定义为字面量<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_886">Literals</a>.
|
<code>nil</code> 和布尔运算中的 <code>true</code> 和 <code>false</code> 现在被定义为字面量<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_886">Literals</a>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Swift 中的数组 (<code>Array</code>) 类型从现在起具备了完整的值语义。具体信息被更新到 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-XID_170">集合的可变性(Mutability of Collections)</a> 和 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-XID_172">数组(Arrays)</a> 两小节,以反映这个新的变化。 此外,还解释了如何 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_150">给Strings, Arrays和Dictionaries进行赋值和拷贝 (Assignment and Copy Behavior for Strings, Arrays, and Dictionaries)</a>.
|
Swift 中的数组 (<code>Array</code>) 类型从现在起具备了完整的值语义。具体信息被更新到 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-XID_170">集合的可变性(Mutability of Collections)</a> 和 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-XID_172">数组(Arrays)</a> 两小节,以反映这个新的变化。 此外,还解释了如何 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_150">给 Strings, Arrays 和 Dictionaries 进行赋值和拷贝 (Assignment and Copy Behavior for Strings, Arrays, and Dictionaries)</a>.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-XID_173">数组类型速记语法(Array Type Shorthand Syntax)</a> 从 <code>SomeType[]</code>.更新为<code>[SomeType]</code>
|
<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-XID_173">数组类型速记语法(Array Type Shorthand Syntax)</a> 从 <code>SomeType[]</code>.更新为<code>[SomeType]</code>
|
||||||
|
|||||||
@ -11,13 +11,13 @@
|
|||||||
> 2.1
|
> 2.1
|
||||||
> 翻译:[Prayer](https://github.com/futantan)
|
> 翻译:[Prayer](https://github.com/futantan)
|
||||||
> 校对:[shanks](http://codebuild.me),[overtrue](https://github.com/overtrue)
|
> 校对:[shanks](http://codebuild.me),[overtrue](https://github.com/overtrue)
|
||||||
>
|
|
||||||
> 2.2
|
> 2.2
|
||||||
> 校对:[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, 2016-11-11,shanks
|
> 3.0.1, 2016-11-11,shanks
|
||||||
|
|
||||||
> 4.0
|
> 4.0
|
||||||
@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 应用的新语言。然而,如果你有 C 或者 Objective-C 开发经验的话,你会发现 Swift 的很多内容都是你熟悉的。
|
Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 应用的新语言。然而,如果你有 C 或者 Objective-C 开发经验的话,你会发现 Swift 的很多内容都是你熟悉的。
|
||||||
|
|
||||||
Swift 包含了 C 和 Objective-C 上所有基础数据类型,`Int`表示整型值; `Double` 和 `Float` 表示浮点型值; `Bool` 是布尔型值;`String` 是文本型数据。 Swift 还提供了三个基本的集合类型,`Array` ,`Set` 和 `Dictionary` ,详见[集合类型](./04_Collection_Types.html)。
|
Swift 包含了 C 和 Objective-C 上所有基础数据类型,`Int` 表示整型值; `Double` 和 `Float` 表示浮点型值; `Bool` 是布尔型值;`String` 是文本型数据。 Swift 还提供了三个基本的集合类型,`Array` ,`Set` 和 `Dictionary` ,详见[集合类型](./04_Collection_Types.html)。
|
||||||
|
|
||||||
就像 C 语言一样,Swift 使用变量来进行存储并通过变量名来关联值。在 Swift 中,广泛的使用着值不可变的变量,它们就是常量,而且比 C 语言的常量更强大。在 Swift 中,如果你要处理的值不需要改变,那使用常量可以让你的代码更加安全并且更清晰地表达你的意图。
|
就像 C 语言一样,Swift 使用变量来进行存储并通过变量名来关联值。在 Swift 中,广泛的使用着值不可变的变量,它们就是常量,而且比 C 语言的常量更强大。在 Swift 中,如果你要处理的值不需要改变,那使用常量可以让你的代码更加安全并且更清晰地表达你的意图。
|
||||||
|
|
||||||
@ -95,7 +95,8 @@ 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>
|
||||||
@ -129,7 +130,7 @@ 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>
|
||||||
### 常量和变量的命名
|
### 常量和变量的命名
|
||||||
@ -148,9 +149,9 @@ let 🐶🐮 = "dogcow"
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 如果你需要使用与Swift保留关键字相同的名称作为常量或者变量名,你可以使用反引号(`)将关键字包围的方式将其作为名字使用。无论如何,你应当避免使用关键字作为常量或变量名,除非你别无选择。
|
> 如果你需要使用与 Swift 保留关键字相同的名称作为常量或者变量名,你可以使用反引号(`)将关键字包围的方式将其作为名字使用。无论如何,你应当避免使用关键字作为常量或变量名,除非你别无选择。
|
||||||
|
|
||||||
你可以更改现有的变量值为其他同类型的值,在下面的例子中,`friendlyWelcome`的值从`"Hello!"`改为了`"Bonjour!"`:
|
你可以更改现有的变量值为其他同类型的值,在下面的例子中,`friendlyWelcome` 的值从 `"Hello!"` 改为了 `"Bonjour!"`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var friendlyWelcome = "Hello!"
|
var friendlyWelcome = "Hello!"
|
||||||
@ -169,7 +170,7 @@ languageName = "Swift++"
|
|||||||
<a name="printing"></a>
|
<a name="printing"></a>
|
||||||
### 输出常量和变量
|
### 输出常量和变量
|
||||||
|
|
||||||
你可以用`print(_:separator:terminator:)`函数来输出当前常量或变量的值:
|
你可以用 `print(_:separator:terminator:)` 函数来输出当前常量或变量的值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
print(friendlyWelcome)
|
print(friendlyWelcome)
|
||||||
@ -232,7 +233,7 @@ let cat = "🐱"; print(cat)
|
|||||||
|
|
||||||
整数就是没有小数部分的数字,比如 `42` 和 `-23` 。整数可以是 `有符号`(正、负、零)或者 `无符号`(正、零)。
|
整数就是没有小数部分的数字,比如 `42` 和 `-23` 。整数可以是 `有符号`(正、负、零)或者 `无符号`(正、零)。
|
||||||
|
|
||||||
Swift 提供了8,16,32和64位的有符号和无符号整数类型。这些整数类型和 C 语言的命名方式很像,比如8位无符号整数类型是`UInt8`,32位有符号整数类型是 `Int32` 。就像 Swift 的其他类型一样,整数类型采用大写命名法。
|
Swift 提供了8,16,32和64位的有符号和无符号整数类型。这些整数类型和 C 语言的命名方式很像,比如8位无符号整数类型是 `UInt8`,32位有符号整数类型是 `Int32` 。就像 Swift 的其他类型一样,整数类型采用大写命名法。
|
||||||
|
|
||||||
<a name="integer_bounds"></a>
|
<a name="integer_bounds"></a>
|
||||||
### 整数范围
|
### 整数范围
|
||||||
@ -244,17 +245,17 @@ let minValue = UInt8.min // minValue 为 0,是 UInt8 类型
|
|||||||
let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型
|
let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型
|
||||||
```
|
```
|
||||||
|
|
||||||
`min` 和 `max` 所传回值的类型,正是其所对的整数类型(如上例UInt8, 所传回的类型是UInt8),可用在表达式中相同类型值旁。
|
`min` 和 `max` 所传回值的类型,正是其所对的整数类型(如上例 UInt8, 所传回的类型是 UInt8),可用在表达式中相同类型值旁。
|
||||||
|
|
||||||
<a name="Int"></a>
|
<a name="Int"></a>
|
||||||
### Int
|
### Int
|
||||||
|
|
||||||
一般来说,你不需要专门指定整数的长度。Swift 提供了一个特殊的整数类型`Int`,长度与当前平台的原生字长相同:
|
一般来说,你不需要专门指定整数的长度。Swift 提供了一个特殊的整数类型 `Int`,长度与当前平台的原生字长相同:
|
||||||
|
|
||||||
* 在32位平台上,`Int` 和 `Int32` 长度相同。
|
* 在32位平台上,`Int` 和 `Int32` 长度相同。
|
||||||
* 在64位平台上,`Int` 和 `Int64` 长度相同。
|
* 在64位平台上,`Int` 和 `Int64` 长度相同。
|
||||||
|
|
||||||
除非你需要特定长度的整数,一般来说使用 `Int` 就够了。这可以提高代码一致性和可复用性。即使是在32位平台上,`Int` 可以存储的整数范围也可以达到 `-2,147,483,648` ~ `2,147,483,647` ,大多数时候这已经足够大了。
|
除非你需要特定长度的整数,一般来说使用 `Int` 就够了。这可以提高代码一致性和可复用性。即使是在32位平台上,`Int` 可以存储的整数范围也可以达到 `-2,147,483,648` ~ `2,147,483,647`,大多数时候这已经足够大了。
|
||||||
|
|
||||||
<a name="UInt"></a>
|
<a name="UInt"></a>
|
||||||
### UInt
|
### UInt
|
||||||
@ -266,7 +267,7 @@ Swift 也提供了一个特殊的无符号类型 `UInt`,长度与当前平台
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 尽量不要使用`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>
|
||||||
## 浮点数
|
## 浮点数
|
||||||
@ -275,17 +276,17 @@ Swift 也提供了一个特殊的无符号类型 `UInt`,长度与当前平台
|
|||||||
|
|
||||||
浮点类型比整数类型表示的范围更大,可以存储比 `Int` 类型更大或者更小的数字。Swift 提供了两种有符号浮点数类型:
|
浮点类型比整数类型表示的范围更大,可以存储比 `Int` 类型更大或者更小的数字。Swift 提供了两种有符号浮点数类型:
|
||||||
|
|
||||||
* `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>
|
||||||
## 类型安全和类型推断
|
## 类型安全和类型推断
|
||||||
|
|
||||||
Swift 是一个*类型安全(type safe)*的语言。类型安全的语言可以让你清楚地知道代码要处理的值的类型。如果你的代码需要一个`String`,你绝对不可能不小心传进去一个`Int`。
|
Swift 是一个*类型安全(type safe)*的语言。类型安全的语言可以让你清楚地知道代码要处理的值的类型。如果你的代码需要一个 `String`,你绝对不可能不小心传进去一个 `Int`。
|
||||||
|
|
||||||
由于 Swift 是类型安全的,所以它会在编译你的代码时进行*类型检查(type checks)*,并把不匹配的类型标记为错误。这可以让你在开发的时候尽早发现并修复错误。
|
由于 Swift 是类型安全的,所以它会在编译你的代码时进行*类型检查(type checks)*,并把不匹配的类型标记为错误。这可以让你在开发的时候尽早发现并修复错误。
|
||||||
|
|
||||||
@ -309,7 +310,7 @@ let pi = 3.14159
|
|||||||
// pi 会被推测为 Double 类型
|
// pi 会被推测为 Double 类型
|
||||||
```
|
```
|
||||||
|
|
||||||
当推断浮点数的类型时,Swift 总是会选择 `Double` 而不是`Float`。
|
当推断浮点数的类型时,Swift 总是会选择 `Double` 而不是 `Float`。
|
||||||
|
|
||||||
如果表达式中同时出现了整数和浮点数,会被推断为 `Double` 类型:
|
如果表达式中同时出现了整数和浮点数,会被推断为 `Double` 类型:
|
||||||
|
|
||||||
@ -326,11 +327,11 @@ let anotherPi = 3 + 0.14159
|
|||||||
整数字面量可以被写作:
|
整数字面量可以被写作:
|
||||||
|
|
||||||
* 一个*十进制*数,没有前缀
|
* 一个*十进制*数,没有前缀
|
||||||
* 一个*二进制*数,前缀是`0b`
|
* 一个*二进制*数,前缀是 `0b`
|
||||||
* 一个*八进制*数,前缀是`0o`
|
* 一个*八进制*数,前缀是 `0o`
|
||||||
* 一个*十六进制*数,前缀是`0x`
|
* 一个*十六进制*数,前缀是 `0x`
|
||||||
|
|
||||||
下面的所有整数字面量的十进制值都是`17`:
|
下面的所有整数字面量的十进制值都是 `17`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let decimalInteger = 17
|
let decimalInteger = 17
|
||||||
@ -341,17 +342,17 @@ let hexadecimalInteger = 0x11 // 十六进制的17
|
|||||||
|
|
||||||
浮点字面量可以是十进制(没有前缀)或者是十六进制(前缀是 `0x` )。小数点两边必须有至少一个十进制数字(或者是十六进制的数字)。十进制浮点数也可以有一个可选的指数(exponent),通过大写或者小写的 `e` 来指定;十六进制浮点数必须有一个指数,通过大写或者小写的 `p` 来指定。
|
浮点字面量可以是十进制(没有前缀)或者是十六进制(前缀是 `0x` )。小数点两边必须有至少一个十进制数字(或者是十六进制的数字)。十进制浮点数也可以有一个可选的指数(exponent),通过大写或者小写的 `e` 来指定;十六进制浮点数必须有一个指数,通过大写或者小写的 `p` 来指定。
|
||||||
|
|
||||||
如果一个十进制数的指数为 `exp`,那这个数相当于基数和10^exp的乘积:
|
如果一个十进制数的指数为 `exp`,那这个数相当于基数和10^exp 的乘积:
|
||||||
|
|
||||||
* `1.25e2` 表示 1.25 × 10^2,等于 `125.0`。
|
* `1.25e2` 表示 1.25 × 10^2,等于 `125.0`。
|
||||||
* `1.25e-2` 表示 1.25 × 10^-2,等于 `0.0125`。
|
* `1.25e-2` 表示 1.25 × 10^-2,等于 `0.0125`。
|
||||||
|
|
||||||
如果一个十六进制数的指数为`exp`,那这个数相当于基数和2^exp的乘积:
|
如果一个十六进制数的指数为 `exp`,那这个数相当于基数和2^exp 的乘积:
|
||||||
|
|
||||||
* `0xFp2` 表示 15 × 2^2,等于 `60.0`。
|
* `0xFp2` 表示 15 × 2^2,等于 `60.0`。
|
||||||
* `0xFp-2` 表示 15 × 2^-2,等于 `3.75`。
|
* `0xFp-2` 表示 15 × 2^-2,等于 `3.75`。
|
||||||
|
|
||||||
下面的这些浮点字面量都等于十进制的`12.1875`:
|
下面的这些浮点字面量都等于十进制的 `12.1875`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let decimalDouble = 12.1875
|
let decimalDouble = 12.1875
|
||||||
@ -370,14 +371,14 @@ let justOverOneMillion = 1_000_000.000_000_1
|
|||||||
<a name="numeric_type_conversion"></a>
|
<a name="numeric_type_conversion"></a>
|
||||||
## 数值型类型转换
|
## 数值型类型转换
|
||||||
|
|
||||||
通常来讲,即使代码中的整数常量和变量已知非负,也请使用`Int`类型。总是使用默认的整数类型可以保证你的整数常量和变量可以直接被复用并且可以匹配整数类字面量的类型推断。
|
通常来讲,即使代码中的整数常量和变量已知非负,也请使用 `Int` 类型。总是使用默认的整数类型可以保证你的整数常量和变量可以直接被复用并且可以匹配整数类字面量的类型推断。
|
||||||
|
|
||||||
只有在必要的时候才使用其他整数类型,比如要处理外部的长度明确的数据或者为了优化性能、内存占用等等。使用显式指定长度的类型可以及时发现值溢出并且可以暗示正在处理特殊数据。
|
只有在必要的时候才使用其他整数类型,比如要处理外部的长度明确的数据或者为了优化性能、内存占用等等。使用显式指定长度的类型可以及时发现值溢出并且可以暗示正在处理特殊数据。
|
||||||
|
|
||||||
<a name="integer_conversion"></a>
|
<a name="integer_conversion"></a>
|
||||||
### 整数转换
|
### 整数转换
|
||||||
|
|
||||||
不同整数类型的变量和常量可以存储不同范围的数字。`Int8`类型的常量或者变量可以存储的数字范围是`-128`~`127`,而`UInt8`类型的常量或者变量能存储的数字范围是`0`~`255`。如果数字超出了常量或者变量可存储的范围,编译的时候会报错:
|
不同整数类型的变量和常量可以存储不同范围的数字。`Int8` 类型的常量或者变量可以存储的数字范围是 `-128`~`127`,而 `UInt8` 类型的常量或者变量能存储的数字范围是 `0`~`255`。如果数字超出了常量或者变量可存储的范围,编译的时候会报错:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let cannotBeNegative: UInt8 = -1
|
let cannotBeNegative: UInt8 = -1
|
||||||
@ -388,7 +389,7 @@ let tooBig: Int8 = Int8.max + 1
|
|||||||
|
|
||||||
由于每种整数类型都可以存储不同范围的值,所以你必须根据不同情况选择性使用数值型类型转换。这种选择性使用的方式,可以预防隐式转换的错误并让你的代码中的类型转换意图变得清晰。
|
由于每种整数类型都可以存储不同范围的值,所以你必须根据不同情况选择性使用数值型类型转换。这种选择性使用的方式,可以预防隐式转换的错误并让你的代码中的类型转换意图变得清晰。
|
||||||
|
|
||||||
要将一种数字类型转换成另一种,你要用当前值来初始化一个期望类型的新数字,这个数字的类型就是你的目标类型。在下面的例子中,常量`twoThousand`是`UInt16`类型,然而常量`one`是`UInt8`类型。它们不能直接相加,因为它们类型不同。所以要调用`UInt16(one)`来创建一个新的`UInt16`数字并用`one`的值来初始化,然后使用这个新数字来计算:
|
要将一种数字类型转换成另一种,你要用当前值来初始化一个期望类型的新数字,这个数字的类型就是你的目标类型。在下面的例子中,常量 `twoThousand` 是 `UInt16` 类型,然而常量 `one` 是 `UInt8` 类型。它们不能直接相加,因为它们类型不同。所以要调用 `UInt16(one)` 来创建一个新的 `UInt16` 数字并用 `one` 的值来初始化,然后使用这个新数字来计算:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let twoThousand: UInt16 = 2_000
|
let twoThousand: UInt16 = 2_000
|
||||||
@ -398,7 +399,7 @@ let twoThousandAndOne = twoThousand + UInt16(one)
|
|||||||
|
|
||||||
现在两个数字的类型都是 `UInt16`,可以进行相加。目标常量 `twoThousandAndOne` 的类型被推断为 `UInt16`,因为它是两个 `UInt16` 值的和。
|
现在两个数字的类型都是 `UInt16`,可以进行相加。目标常量 `twoThousandAndOne` 的类型被推断为 `UInt16`,因为它是两个 `UInt16` 值的和。
|
||||||
|
|
||||||
`SomeType(ofInitialValue)` 是调用 Swift 构造器并传入一个初始值的默认方法。在语言内部,`UInt16` 有一个构造器,可以接受一个`UInt8`类型的值,所以这个构造器可以用现有的 `UInt8` 来创建一个新的 `UInt16`。注意,你并不能传入任意类型的值,只能传入 `UInt16` 内部有对应构造器的值。不过你可以扩展现有的类型来让它可以接收其他类型的值(包括自定义类型),请参考[扩展](./20_Extensions.html)。
|
`SomeType(ofInitialValue)` 是调用 Swift 构造器并传入一个初始值的默认方法。在语言内部,`UInt16` 有一个构造器,可以接受一个 `UInt8` 类型的值,所以这个构造器可以用现有的 `UInt8` 来创建一个新的 `UInt16`。注意,你并不能传入任意类型的值,只能传入 `UInt16` 内部有对应构造器的值。不过你可以扩展现有的类型来让它可以接收其他类型的值(包括自定义类型),请参考[扩展](./20_Extensions.html)。
|
||||||
|
|
||||||
<a name="integer_and_floating_point_conversion"></a>
|
<a name="integer_and_floating_point_conversion"></a>
|
||||||
### 整数和浮点数转换
|
### 整数和浮点数转换
|
||||||
@ -425,12 +426,12 @@ let integerPi = Int(pi)
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 结合数字类常量和变量不同于结合数字类字面量。字面量`3`可以直接和字面量`0.14159`相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测。
|
> 结合数字类常量和变量不同于结合数字类字面量。字面量 `3` 可以直接和字面量 `0.14159` 相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测。
|
||||||
|
|
||||||
<a name="type_aliases"></a>
|
<a name="type_aliases"></a>
|
||||||
## 类型别名
|
## 类型别名
|
||||||
|
|
||||||
*类型别名(type aliases)*就是给现有类型定义另一个名字。你可以使用`typealias`关键字来定义类型别名。
|
*类型别名(type aliases)*就是给现有类型定义另一个名字。你可以使用 `typealias` 关键字来定义类型别名。
|
||||||
|
|
||||||
当你想要给现有类型起一个更有意义的名字时,类型别名非常有用。假设你正在处理特定长度的外部资源的数据:
|
当你想要给现有类型起一个更有意义的名字时,类型别名非常有用。假设你正在处理特定长度的外部资源的数据:
|
||||||
|
|
||||||
@ -445,12 +446,12 @@ var maxAmplitudeFound = AudioSample.min
|
|||||||
// maxAmplitudeFound 现在是 0
|
// maxAmplitudeFound 现在是 0
|
||||||
```
|
```
|
||||||
|
|
||||||
本例中,`AudioSample`被定义为`UInt16`的一个别名。因为它是别名,`AudioSample.min`实际上是`UInt16.min`,所以会给`maxAmplitudeFound`赋一个初值`0`。
|
本例中,`AudioSample` 被定义为 `UInt16` 的一个别名。因为它是别名,`AudioSample.min` 实际上是 `UInt16.min`,所以会给 `maxAmplitudeFound` 赋一个初值 `0`。
|
||||||
|
|
||||||
<a name="booleans"></a>
|
<a name="booleans"></a>
|
||||||
## 布尔值
|
## 布尔值
|
||||||
|
|
||||||
Swift 有一个基本的*布尔(Boolean)类型*,叫做`Bool`。布尔值指*逻辑*上的值,因为它们只能是真或者假。Swift 有两个布尔常量,`true` 和 `false`:
|
Swift 有一个基本的*布尔(Boolean)类型*,叫做 `Bool`。布尔值指*逻辑*上的值,因为它们只能是真或者假。Swift 有两个布尔常量,`true` 和 `false`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let orangesAreOrange = true
|
let orangesAreOrange = true
|
||||||
@ -470,7 +471,7 @@ if turnipsAreDelicious {
|
|||||||
// 输出 "Eww, turnips are horrible."
|
// 输出 "Eww, turnips are horrible."
|
||||||
```
|
```
|
||||||
|
|
||||||
条件语句,例如`if`,请参考[控制流](./05_Control_Flow.html)。
|
条件语句,例如 `if`,请参考[控制流](./05_Control_Flow.html)。
|
||||||
|
|
||||||
如果你在需要使用 `Bool` 类型的地方使用了非布尔值,Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误:
|
如果你在需要使用 `Bool` 类型的地方使用了非布尔值,Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误:
|
||||||
|
|
||||||
@ -566,7 +567,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"` 不行。
|
||||||
|
|
||||||
@ -583,7 +584,7 @@ let convertedNumber = Int(possibleNumber)
|
|||||||
<a name="nil"></a>
|
<a name="nil"></a>
|
||||||
### nil
|
### nil
|
||||||
|
|
||||||
你可以给可选变量赋值为`nil`来表示它没有值:
|
你可以给可选变量赋值为 `nil` 来表示它没有值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var serverResponseCode: Int? = 404
|
var serverResponseCode: Int? = 404
|
||||||
@ -594,7 +595,7 @@ serverResponseCode = nil
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> `nil`不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失的情况,请把它们声明成对应的可选类型。
|
> `nil` 不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失的情况,请把它们声明成对应的可选类型。
|
||||||
|
|
||||||
如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为 `nil`:
|
如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为 `nil`:
|
||||||
|
|
||||||
@ -649,7 +650,7 @@ if let constantName = someOptional {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
你可以像上面这样使用可选绑定来重写 在[可选类型](./01_The_Basics.html#optionals)举出的`possibleNumber`例子:
|
你可以像上面这样使用可选绑定来重写 在[可选类型](./01_The_Basics.html#optionals)举出的 `possibleNumber` 例子:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let actualNumber = Int(possibleNumber) {
|
if let actualNumber = Int(possibleNumber) {
|
||||||
@ -666,9 +667,9 @@ if let actualNumber = Int(possibleNumber) {
|
|||||||
|
|
||||||
如果转换成功,`actualNumber` 常量可以在 `if` 语句的第一个分支中使用。它已经被可选类型 *包含的* 值初始化过,所以不需要再使用 `!` 后缀来获取它的值。在这个例子中,`actualNumber` 只被用来输出转换结果。
|
如果转换成功,`actualNumber` 常量可以在 `if` 语句的第一个分支中使用。它已经被可选类型 *包含的* 值初始化过,所以不需要再使用 `!` 后缀来获取它的值。在这个例子中,`actualNumber` 只被用来输出转换结果。
|
||||||
|
|
||||||
你可以在可选绑定中使用常量和变量。如果你想在`if`语句的第一个分支中操作 `actualNumber` 的值,你可以改成 `if var actualNumber`,这样可选类型包含的值就会被赋给一个变量而非常量。
|
你可以在可选绑定中使用常量和变量。如果你想在 `if` 语句的第一个分支中操作 `actualNumber` 的值,你可以改成 `if var actualNumber`,这样可选类型包含的值就会被赋给一个变量而非常量。
|
||||||
|
|
||||||
你可以包含多个可选绑定或多个布尔条件在一个 `if` 语句中,只要使用逗号分开就行。只要有任意一个可选绑定的值为`nil`,或者任意一个布尔条件为`false`,则整个`if`条件判断为`false`,这时你就需要使用嵌套 `if` 条件语句来处理,如下所示:
|
你可以包含多个可选绑定或多个布尔条件在一个 `if` 语句中,只要使用逗号分开就行。只要有任意一个可选绑定的值为 `nil`,或者任意一个布尔条件为 `false`,则整个 `if` 条件判断为 `false`,这时你就需要使用嵌套 `if` 条件语句来处理,如下所示:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
|
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
|
||||||
@ -737,7 +738,7 @@ if let definiteString = assumedString {
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 如果一个变量之后可能变成`nil`的话请不要使用隐式解析可选类型。如果你需要在变量的生命周期中判断是否是`nil`的话,请使用普通可选类型。
|
> 如果一个变量之后可能变成 `nil` 的话请不要使用隐式解析可选类型。如果你需要在变量的生命周期中判断是否是 `nil` 的话,请使用普通可选类型。
|
||||||
|
|
||||||
<a name="error_handling"></a>
|
<a name="error_handling"></a>
|
||||||
## 错误处理
|
## 错误处理
|
||||||
@ -754,7 +755,7 @@ func canThrowAnError() throws {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
一个函数可以通过在声明中添加`throws`关键词来抛出错误消息。当你的函数能抛出错误消息时,你应该在表达式中前置`try`关键词。
|
一个函数可以通过在声明中添加 `throws` 关键词来抛出错误消息。当你的函数能抛出错误消息时,你应该在表达式中前置 `try` 关键词。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
do {
|
do {
|
||||||
@ -765,7 +766,7 @@ do {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
一个`do`语句创建了一个新的包含作用域,使得错误能被传播到一个或多个`catch`从句。
|
一个 `do` 语句创建了一个新的包含作用域,使得错误能被传播到一个或多个 `catch` 从句。
|
||||||
|
|
||||||
这里有一个错误处理如何用来应对不同错误条件的例子。
|
这里有一个错误处理如何用来应对不同错误条件的例子。
|
||||||
|
|
||||||
@ -793,7 +794,7 @@ do {
|
|||||||
<a name="assertions_and_Preconditions"></a>
|
<a name="assertions_and_Preconditions"></a>
|
||||||
## 断言和先决条件
|
## 断言和先决条件
|
||||||
|
|
||||||
断言和先决条件是在运行时所做的检查。你可以用他们来检查在执行后续代码之前是否一个必要的条件已经被满足了。如果断言或者先决条件中的布尔条件评估的结果为 true(真),则代码像往常一样继续执行。如果布尔条件评估结果为false(假),程序的当前状态是无效的,则代码执行结束,应用程序中止。
|
断言和先决条件是在运行时所做的检查。你可以用他们来检查在执行后续代码之前是否一个必要的条件已经被满足了。如果断言或者先决条件中的布尔条件评估的结果为 true(真),则代码像往常一样继续执行。如果布尔条件评估结果为 false(假),程序的当前状态是无效的,则代码执行结束,应用程序中止。
|
||||||
|
|
||||||
你使用断言和先决条件来表达你所做的假设和你在编码时候的期望。你可以将这些包含在你的代码中。断言帮助你在开发阶段找到错误和不正确的假设,先决条件帮助你在生产环境中探测到存在的问题。
|
你使用断言和先决条件来表达你所做的假设和你在编码时候的期望。你可以将这些包含在你的代码中。断言帮助你在开发阶段找到错误和不正确的假设,先决条件帮助你在生产环境中探测到存在的问题。
|
||||||
|
|
||||||
@ -821,7 +822,7 @@ assert(age >= 0, "A person's age cannot be less than zero")
|
|||||||
assert(age >= 0)
|
assert(age >= 0)
|
||||||
```
|
```
|
||||||
|
|
||||||
如果代码已经检查了条件,你可以使用 `assertionFailure(_:file:line:)`函数来表明断言失败了,例如:
|
如果代码已经检查了条件,你可以使用 `assertionFailure(_:file:line:)` 函数来表明断言失败了,例如:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if age > 10 {
|
if age > 10 {
|
||||||
@ -844,10 +845,10 @@ if age > 10 {
|
|||||||
precondition(index > 0, "Index must be greater than zero.")
|
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 不会像断言和先决条件那样被优化掉,所以你可以确保当代码执行到一个没有被实现的方法时,程序会被中断。
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
*运算符*是检查、改变、合并值的特殊符号或短语。例如,加号(`+`)将两个数相加(如 `let i = 1 + 2`)。更复杂的运算例子包括逻辑与运算符 `&&`(如 `if enteredDoorCode && passedRetinaScan`)。
|
*运算符*是检查、改变、合并值的特殊符号或短语。例如,加号(`+`)将两个数相加(如 `let i = 1 + 2`)。更复杂的运算例子包括逻辑与运算符 `&&`(如 `if enteredDoorCode && passedRetinaScan`)。
|
||||||
|
|
||||||
Swift 支持大部分标准 C 语言的运算符,且改进许多特性来减少常规编码错误。如:赋值符(`=`)不返回值,以防止把想要判断相等运算符(`==`)的地方写成赋值符导致的错误。算术运算符(`+`,`-`,`*`,`/`,`%`等)会检测并不允许值溢出,以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然允许你使用 Swift 的溢出运算符来实现溢出。详情参见[溢出运算符](./26_Advanced_Operators.html#overflow_operators)。
|
Swift 支持大部分标准 C 语言的运算符,且改进许多特性来减少常规编码错误。如:赋值符(`=`)不返回值,以防止把想要判断相等运算符(`==`)的地方写成赋值符导致的错误。算术运算符(`+`,`-`,`*`,`/`,`%` 等)会检测并不允许值溢出,以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然允许你使用 Swift 的溢出运算符来实现溢出。详情参见[溢出运算符](./26_Advanced_Operators.html#overflow_operators)。
|
||||||
|
|
||||||
Swift 还提供了 C 语言没有的区间运算符,例如 `a..<b` 或 `a...b`,这方便我们表达一个区间内的数值。
|
Swift 还提供了 C 语言没有的区间运算符,例如 `a..<b` 或 `a...b`,这方便我们表达一个区间内的数值。
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ Swift 中所有数值类型都支持了基本的四则*算术运算符*:
|
|||||||
|
|
||||||
### 求余运算符
|
### 求余运算符
|
||||||
|
|
||||||
*求余运算符*(`a % b`)是计算 `b` 的多少倍刚刚好可以容入`a`,返回多出来的那部分(余数)。
|
*求余运算符*(`a % b`)是计算 `b` 的多少倍刚刚好可以容入 `a`,返回多出来的那部分(余数)。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
@ -126,11 +126,11 @@ Swift 中所有数值类型都支持了基本的四则*算术运算符*:
|
|||||||
9 % 4 // 等于 1
|
9 % 4 // 等于 1
|
||||||
```
|
```
|
||||||
|
|
||||||
为了得到 `a % b` 的结果,`%` 计算了以下等式,并输出`余数`作为结果:
|
为了得到 `a % b` 的结果,`%` 计算了以下等式,并输出 `余数`作为结果:
|
||||||
|
|
||||||
a = (b × 倍数) + 余数
|
a = (b × 倍数) + 余数
|
||||||
|
|
||||||
当`倍数`取最大值的时候,就会刚好可以容入 `a` 中。
|
当 `倍数`取最大值的时候,就会刚好可以容入 `a` 中。
|
||||||
|
|
||||||
把 `9` 和 `4` 代入等式中,我们得 `1`:
|
把 `9` 和 `4` 代入等式中,我们得 `1`:
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ 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)。
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ a += 2
|
|||||||
2 <= 1 // false, 因为 2 并不小于等于 1
|
2 <= 1 // false, 因为 2 并不小于等于 1
|
||||||
```
|
```
|
||||||
|
|
||||||
比较运算多用于条件语句,如`if`条件:
|
比较运算多用于条件语句,如 `if` 条件:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let name = "world"
|
let name = "world"
|
||||||
@ -241,7 +241,7 @@ if name == "world" {
|
|||||||
(4, "dog") == (4, "dog") // true,因为 4 等于 4,dog 等于 dog
|
(4, "dog") == (4, "dog") // true,因为 4 等于 4,dog 等于 dog
|
||||||
```
|
```
|
||||||
|
|
||||||
在上面的例子中,你可以看到,在第一行中从左到右的比较行为。因为`1`小于`2`,所以`(1, "zebra")`小于`(2, "apple")`,不管元组剩下的值如何。所以`"zebra"`大于`"apple"`对结果没有任何影响,因为元组的比较结果已经被第一个元素决定了。不过,当元组的第一个元素相同时候,第二个元素将会用作比较-第二行和第三行代码就发生了这样的比较。
|
在上面的例子中,你可以看到,在第一行中从左到右的比较行为。因为 `1` 小于 `2`,所以 `(1, "zebra")` 小于 `(2, "apple")`,不管元组剩下的值如何。所以 `"zebra"` 大于 `"apple"` 对结果没有任何影响,因为元组的比较结果已经被第一个元素决定了。不过,当元组的第一个元素相同时候,第二个元素将会用作比较-第二行和第三行代码就发生了这样的比较。
|
||||||
|
|
||||||
当元组中的元素都可以被比较时,你也可以使用这些运算符来比较它们的大小。例如,像下面展示的代码,你可以比较两个类型为 `(String, Int)` 的元组,因为 `Int` 和 `String` 类型的值可以比较。相反,`Bool` 不能被比较,也意味着存有布尔类型的元组不能被比较。
|
当元组中的元素都可以被比较时,你也可以使用这些运算符来比较它们的大小。例如,像下面展示的代码,你可以比较两个类型为 `(String, Int)` 的元组,因为 `Int` 和 `String` 类型的值可以比较。相反,`Bool` 不能被比较,也意味着存有布尔类型的元组不能被比较。
|
||||||
|
|
||||||
@ -250,9 +250,9 @@ 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>
|
||||||
## 三元运算符(Ternary Conditional Operator)
|
## 三元运算符(Ternary Conditional Operator)
|
||||||
@ -356,7 +356,7 @@ for index in 1...5 {
|
|||||||
// 5 * 5 = 25
|
// 5 * 5 = 25
|
||||||
```
|
```
|
||||||
|
|
||||||
关于 `for-in`循环,请看[控制流](./05_Control_Flow.html)。
|
关于 `for-in` 循环,请看[控制流](./05_Control_Flow.html)。
|
||||||
|
|
||||||
|
|
||||||
### 半开区间运算符
|
### 半开区间运算符
|
||||||
|
|||||||
@ -42,19 +42,19 @@
|
|||||||
- [比较字符串](#comparing_strings)
|
- [比较字符串](#comparing_strings)
|
||||||
- [字符串的 Unicode 表示形式](#unicode_representations_of_strings)
|
- [字符串的 Unicode 表示形式](#unicode_representations_of_strings)
|
||||||
|
|
||||||
*字符串*是是一系列字符的集合,例如`"hello, world"`,`"albatross"`。Swift的字符串通过`String`类型来表示。
|
*字符串*是是一系列字符的集合,例如 `"hello, world"`,`"albatross"`。Swift 的字符串通过 `String` 类型来表示。
|
||||||
一个`String`的内容可以用许多方式读取,包括作为一个`Character`值的集合。
|
一个 `String` 的内容可以用许多方式读取,包括作为一个 `Character` 值的集合。
|
||||||
|
|
||||||
Swift 的`String`和`Character`类型提供了快速和兼容 Unicode 的方式供你的代码使用。创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。字符串连接操作只需要简单地通过`+`符号将两个字符串相连即可。与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。你也可以在字符串内插过程中使用字符串插入常量、变量、字面量表达成更长的字符串,这样可以很容易的创建自定义的字符串值,进行展示、存储以及打印。
|
Swift 的 `String` 和 `Character` 类型提供了快速和兼容 Unicode 的方式供你的代码使用。创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。字符串连接操作只需要简单地通过 `+` 符号将两个字符串相连即可。与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。你也可以在字符串内插过程中使用字符串插入常量、变量、字面量表达成更长的字符串,这样可以很容易的创建自定义的字符串值,进行展示、存储以及打印。
|
||||||
|
|
||||||
尽管语法简易,但`String`类型是一种快速、现代化的字符串实现。
|
尽管语法简易,但 `String` 类型是一种快速、现代化的字符串实现。
|
||||||
每一个字符串都是由编码无关的 Unicode 字符组成,并支持访问字符的多种 Unicode 表示形式。
|
每一个字符串都是由编码无关的 Unicode 字符组成,并支持访问字符的多种 Unicode 表示形式。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 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>
|
||||||
## 字符串字面量
|
## 字符串字面量
|
||||||
@ -67,7 +67,7 @@ Swift 的`String`和`Character`类型提供了快速和兼容 Unicode 的方式
|
|||||||
let someString = "Some string literal value"
|
let someString = "Some string literal value"
|
||||||
```
|
```
|
||||||
|
|
||||||
注意`someString`常量通过字符串字面量进行初始化,Swift 会推断该常量为`String`类型。
|
注意 `someString` 常量通过字符串字面量进行初始化,Swift 会推断该常量为 `String` 类型。
|
||||||
|
|
||||||
<a name="multiline_string_literals"></a>
|
<a name="multiline_string_literals"></a>
|
||||||
### 多行字符串字面量
|
### 多行字符串字面量
|
||||||
@ -116,7 +116,7 @@ It also ends with a line break.
|
|||||||
"""
|
"""
|
||||||
```
|
```
|
||||||
|
|
||||||
一个多行字符串字面量能够缩进来匹配周围的代码。关闭引号(`"""`)之前的空白字符串告诉Swift编译器其他各行多少空白字符串需要忽略。然而,如果你在某行的前面写的空白字符串超出了关闭引号(`"""`)之前的空白字符串,则超出部分将被包含在多行字符串字面量中。
|
一个多行字符串字面量能够缩进来匹配周围的代码。关闭引号(`"""`)之前的空白字符串告诉 Swift 编译器其他各行多少空白字符串需要忽略。然而,如果你在某行的前面写的空白字符串超出了关闭引号(`"""`)之前的空白字符串,则超出部分将被包含在多行字符串字面量中。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@ -127,12 +127,12 @@ It also ends with a line break.
|
|||||||
|
|
||||||
字符串字面量可以包含以下特殊字符:
|
字符串字面量可以包含以下特殊字符:
|
||||||
|
|
||||||
* 转义字符`\0`(空字符)、`\\`(反斜线)、`\t`(水平制表符)、`\n`(换行符)、`\r`(回车符)、`\"`(双引号)、`\'`(单引号)。
|
* 转义字符 `\0`(空字符)、`\\`(反斜线)、`\t`(水平制表符)、`\n`(换行符)、`\r`(回车符)、`\"`(双引号)、`\'`(单引号)。
|
||||||
* Unicode 标量,写成`\u{n}`(u为小写),其中`n`为任意一到八位十六进制数且可用的 Unicode 位码。
|
* Unicode 标量,写成 `\u{n}`(u 为小写),其中 `n` 为任意一到八位十六进制数且可用的 Unicode 位码。
|
||||||
|
|
||||||
下面的代码为各种特殊字符的使用示例。
|
下面的代码为各种特殊字符的使用示例。
|
||||||
`wiseWords`常量包含了两个双引号。
|
`wiseWords` 常量包含了两个双引号。
|
||||||
`dollarSign`、`blackHeart`和`sparklingHeart`常量演示了三种不同格式的 Unicode 标量:
|
`dollarSign`、`blackHeart` 和 `sparklingHeart` 常量演示了三种不同格式的 Unicode 标量:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
|
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
|
||||||
@ -154,7 +154,7 @@ Escaping all three quotes \"\"\"
|
|||||||
<a name="initializing_an_empty_string"></a>
|
<a name="initializing_an_empty_string"></a>
|
||||||
## 初始化空字符串
|
## 初始化空字符串
|
||||||
|
|
||||||
要创建一个空字符串作为初始值,可以将空的字符串字面量赋值给变量,也可以初始化一个新的`String`实例:
|
要创建一个空字符串作为初始值,可以将空的字符串字面量赋值给变量,也可以初始化一个新的 `String` 实例:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var emptyString = "" // 空字符串字面量
|
var emptyString = "" // 空字符串字面量
|
||||||
@ -162,7 +162,7 @@ var anotherEmptyString = String() // 初始化方法
|
|||||||
// 两个字符串均为空并等价。
|
// 两个字符串均为空并等价。
|
||||||
```
|
```
|
||||||
|
|
||||||
您可以通过检查其`Bool`类型的`isEmpty`属性来判断该字符串是否为空:
|
您可以通过检查其 `Bool` 类型的 `isEmpty` 属性来判断该字符串是否为空:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if emptyString.isEmpty {
|
if emptyString.isEmpty {
|
||||||
@ -188,12 +188,12 @@ constantString += " and another Highlander"
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 在 Objective-C 和 Cocoa 中,您需要通过选择两个不同的类(`NSString`和`NSMutableString`)来指定字符串是否可以被修改。
|
> 在 Objective-C 和 Cocoa 中,您需要通过选择两个不同的类(`NSString` 和 `NSMutableString`)来指定字符串是否可以被修改。
|
||||||
|
|
||||||
<a name="strings_are_value_types"></a>
|
<a name="strings_are_value_types"></a>
|
||||||
## 字符串是值类型
|
## 字符串是值类型
|
||||||
|
|
||||||
Swift 的`String`类型是*值类型*。
|
Swift 的 `String` 类型是*值类型*。
|
||||||
如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。
|
如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。
|
||||||
任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作。
|
任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作。
|
||||||
值类型在 [结构体和枚举是值类型](./09_Classes_and_Structures.html#structures_and_enumerations_are_value_types) 中进行了详细描述。
|
值类型在 [结构体和枚举是值类型](./09_Classes_and_Structures.html#structures_and_enumerations_are_value_types) 中进行了详细描述。
|
||||||
@ -207,7 +207,7 @@ Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字
|
|||||||
<a name="working_with_characters"></a>
|
<a name="working_with_characters"></a>
|
||||||
## 使用字符
|
## 使用字符
|
||||||
|
|
||||||
您可通过`for-in`循环来遍历字符串,获取字符串中每一个字符的值:
|
您可通过 `for-in` 循环来遍历字符串,获取字符串中每一个字符的值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
for character in "Dog!🐶" {
|
for character in "Dog!🐶" {
|
||||||
@ -220,14 +220,14 @@ for character in "Dog!🐶" {
|
|||||||
// 🐶
|
// 🐶
|
||||||
```
|
```
|
||||||
|
|
||||||
`for-in`循环在 [For 循环](./05_Control_Flow.html#for_loops) 中进行了详细描述。
|
`for-in` 循环在 [For 循环](./05_Control_Flow.html#for_loops) 中进行了详细描述。
|
||||||
|
|
||||||
另外,通过标明一个`Character`类型并用字符字面量进行赋值,可以建立一个独立的字符常量或变量:
|
另外,通过标明一个 `Character` 类型并用字符字面量进行赋值,可以建立一个独立的字符常量或变量:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let exclamationMark: Character = "!"
|
let exclamationMark: Character = "!"
|
||||||
```
|
```
|
||||||
字符串可以通过传递一个值类型为`Character`的数组作为自变量来初始化:
|
字符串可以通过传递一个值类型为 `Character` 的数组作为自变量来初始化:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
|
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
|
||||||
@ -256,7 +256,7 @@ instruction += string2
|
|||||||
// instruction 现在等于 "look over there"
|
// instruction 现在等于 "look over there"
|
||||||
```
|
```
|
||||||
|
|
||||||
您可以用`append()`方法将一个字符附加到一个字符串变量的尾部:
|
您可以用 `append()` 方法将一个字符附加到一个字符串变量的尾部:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let exclamationMark: Character = "!"
|
let exclamationMark: Character = "!"
|
||||||
@ -309,12 +309,12 @@ let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
|
|||||||
// message 是 "3 times 2.5 is 7.5"
|
// message 是 "3 times 2.5 is 7.5"
|
||||||
```
|
```
|
||||||
|
|
||||||
在上面的例子中,`multiplier`作为`\(multiplier)`被插入到一个字符串常量量中。
|
在上面的例子中,`multiplier` 作为 `\(multiplier)` 被插入到一个字符串常量量中。
|
||||||
当创建字符串执行插值计算时此占位符会被替换为`multiplier`实际的值。
|
当创建字符串执行插值计算时此占位符会被替换为 `multiplier` 实际的值。
|
||||||
|
|
||||||
`multiplier`的值也作为字符串中后面表达式的一部分。
|
`multiplier` 的值也作为字符串中后面表达式的一部分。
|
||||||
该表达式计算`Double(multiplier) * 2.5`的值并将结果 (`7.5`) 插入到字符串中。
|
该表达式计算 `Double(multiplier) * 2.5` 的值并将结果 (`7.5`) 插入到字符串中。
|
||||||
在这个例子中,表达式写为`\(Double(multiplier) * 2.5)`并包含在字符串字面量中。
|
在这个例子中,表达式写为 `\(Double(multiplier) * 2.5)` 并包含在字符串字面量中。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
@ -325,31 +325,31 @@ let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
|
|||||||
|
|
||||||
*Unicode*是一个国际标准,用于文本的编码和表示。
|
*Unicode*是一个国际标准,用于文本的编码和表示。
|
||||||
它使您可以用标准格式表示来自任意语言几乎所有的字符,并能够对文本文件或网页这样的外部资源中的字符进行读写操作。
|
它使您可以用标准格式表示来自任意语言几乎所有的字符,并能够对文本文件或网页这样的外部资源中的字符进行读写操作。
|
||||||
Swift 的`String`和`Character`类型是完全兼容 Unicode 标准的。
|
Swift 的 `String` 和 `Character` 类型是完全兼容 Unicode 标准的。
|
||||||
|
|
||||||
<a name="unicode_scalars"></a>
|
<a name="unicode_scalars"></a>
|
||||||
### Unicode 标量
|
### Unicode 标量
|
||||||
|
|
||||||
Swift 的`String`类型是基于 *Unicode 标量* 建立的。
|
Swift 的 `String` 类型是基于 *Unicode 标量* 建立的。
|
||||||
Unicode 标量是对应字符或者修饰符的唯一的21位数字,例如`U+0061`表示小写的拉丁字母(`LATIN SMALL LETTER A`)("`a`"),`U+1F425`表示小鸡表情(`FRONT-FACING BABY CHICK`) ("`🐥`")。
|
Unicode 标量是对应字符或者修饰符的唯一的21位数字,例如 `U+0061` 表示小写的拉丁字母(`LATIN SMALL LETTER A`)("`a`"),`U+1F425` 表示小鸡表情(`FRONT-FACING BABY CHICK`) ("`🐥`")。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> Unicode *码位(code poing)* 的范围是`U+0000`到`U+D7FF`或者`U+E000`到`U+10FFFF`。Unicode 标量不包括 Unicode *代理项(surrogate pair)* 码位,其码位范围是`U+D800`到`U+DFFF`。
|
> Unicode *码位(code poing)* 的范围是 `U+0000` 到 `U+D7FF` 或者 `U+E000` 到 `U+10FFFF`。Unicode 标量不包括 Unicode *代理项(surrogate pair)* 码位,其码位范围是 `U+D800` 到 `U+DFFF`。
|
||||||
|
|
||||||
注意不是所有的21位 Unicode 标量都代表一个字符,因为有一些标量是留作未来分配的。已经代表一个典型字符的标量都有自己的名字,例如上面例子中的`LATIN SMALL LETTER A`和`FRONT-FACING BABY CHICK`。
|
注意不是所有的21位 Unicode 标量都代表一个字符,因为有一些标量是留作未来分配的。已经代表一个典型字符的标量都有自己的名字,例如上面例子中的 `LATIN SMALL LETTER A` 和 `FRONT-FACING BABY CHICK`。
|
||||||
|
|
||||||
<a name="special_characters_in_string_literals"></a>
|
<a name="special_characters_in_string_literals"></a>
|
||||||
|
|
||||||
<a name="extended_grapheme_clusters"></a>
|
<a name="extended_grapheme_clusters"></a>
|
||||||
### 可扩展的字形群集
|
### 可扩展的字形群集
|
||||||
|
|
||||||
每一个 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` 转换成了 `é`。
|
||||||
|
|
||||||
在这两种情况中,字母`é`代表了一个单一的 Swift 的`Character`值,同时代表了一个可扩展的字形群。
|
在这两种情况中,字母 `é` 代表了一个单一的 Swift 的 `Character` 值,同时代表了一个可扩展的字形群。
|
||||||
在第一种情况,这个字形群包含一个单一标量;而在第二种情况,它是包含两个标量的字形群:
|
在第一种情况,这个字形群包含一个单一标量;而在第二种情况,它是包含两个标量的字形群:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
@ -358,9 +358,9 @@ let combinedEAcute: Character = "\u{65}\u{301}" // e 后面加上 ́
|
|||||||
// eAcute 是 é, combinedEAcute 是 é
|
// eAcute 是 é, combinedEAcute 是 é
|
||||||
```
|
```
|
||||||
|
|
||||||
可扩展的字符群集是一个灵活的方法,用许多复杂的脚本字符表示单一的`Character`值。
|
可扩展的字符群集是一个灵活的方法,用许多复杂的脚本字符表示单一的 `Character` 值。
|
||||||
例如,来自朝鲜语字母表的韩语音节能表示为组合或分解的有序排列。
|
例如,来自朝鲜语字母表的韩语音节能表示为组合或分解的有序排列。
|
||||||
在 Swift 都会表示为同一个单一的`Character`值:
|
在 Swift 都会表示为同一个单一的 `Character` 值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let precomposed: Character = "\u{D55C}" // 한
|
let precomposed: Character = "\u{D55C}" // 한
|
||||||
@ -368,14 +368,14 @@ let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
|
|||||||
// precomposed 是 한, decomposed 是 한
|
// precomposed 是 한, decomposed 是 한
|
||||||
```
|
```
|
||||||
|
|
||||||
可拓展的字符群集可以使包围记号(例如`COMBINING ENCLOSING CIRCLE`或者`U+20DD`)的标量包围其他 Unicode 标量,作为一个单一的`Character`值:
|
可拓展的字符群集可以使包围记号(例如 `COMBINING ENCLOSING CIRCLE` 或者 `U+20DD`)的标量包围其他 Unicode 标量,作为一个单一的 `Character` 值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
|
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
|
||||||
// enclosedEAcute 是 é⃝
|
// enclosedEAcute 是 é⃝
|
||||||
```
|
```
|
||||||
|
|
||||||
地域性指示符号的 Unicode 标量可以组合成一个单一的`Character`值,例如`REGIONAL INDICATOR SYMBOL LETTER U`(`U+1F1FA`)和`REGIONAL INDICATOR SYMBOL LETTER S`(`U+1F1F8`):
|
地域性指示符号的 Unicode 标量可以组合成一个单一的 `Character` 值,例如 `REGIONAL INDICATOR SYMBOL LETTER U`(`U+1F1FA`)和 `REGIONAL INDICATOR SYMBOL LETTER S`(`U+1F1F8`):
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
|
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
|
||||||
@ -385,7 +385,7 @@ let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
|
|||||||
<a name="counting_characters"></a>
|
<a name="counting_characters"></a>
|
||||||
## 计算字符数量
|
## 计算字符数量
|
||||||
|
|
||||||
如果想要获得一个字符串中`Character`值的数量,可以使用`count`属性:
|
如果想要获得一个字符串中 `Character` 值的数量,可以使用 `count` 属性:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
|
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
|
||||||
@ -393,9 +393,9 @@ print("unusualMenagerie has \(unusualMenagerie.count) characters")
|
|||||||
// 打印输出 "unusualMenagerie has 40 characters"
|
// 打印输出 "unusualMenagerie has 40 characters"
|
||||||
```
|
```
|
||||||
|
|
||||||
注意在 Swift 中,使用可拓展的字符群集作为`Character`值来连接或改变字符串时,并不一定会更改字符串的字符数量。
|
注意在 Swift 中,使用可拓展的字符群集作为 `Character` 值来连接或改变字符串时,并不一定会更改字符串的字符数量。
|
||||||
|
|
||||||
例如,如果你用四个字符的单词`cafe`初始化一个新的字符串,然后添加一个`COMBINING ACTUE ACCENT`(`U+0301`)作为字符串的结尾。最终这个字符串的字符数量仍然是`4`,因为第四个字符是`é`,而不是`e`:
|
例如,如果你用四个字符的单词 `cafe` 初始化一个新的字符串,然后添加一个 `COMBINING ACTUE ACCENT`(`U+0301`)作为字符串的结尾。最终这个字符串的字符数量仍然是 `4`,因为第四个字符是 `é`,而不是 `e`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var word = "cafe"
|
var word = "cafe"
|
||||||
@ -410,9 +410,9 @@ print("the number of characters in \(word) is \(word.count)")
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 可扩展的字符群集可以组成一个或者多个 Unicode 标量。这意味着不同的字符以及相同字符的不同表示方式可能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间数量。因此在没有获取字符串的可扩展的字符群的范围时候,就不能计算出字符串的字符数量。如果您正在处理一个长字符串,需要注意`count`属性必须遍历全部的 Unicode 标量,来确定字符串的字符数量。
|
> 可扩展的字符群集可以组成一个或者多个 Unicode 标量。这意味着不同的字符以及相同字符的不同表示方式可能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间数量。因此在没有获取字符串的可扩展的字符群的范围时候,就不能计算出字符串的字符数量。如果您正在处理一个长字符串,需要注意 `count` 属性必须遍历全部的 Unicode 标量,来确定字符串的字符数量。
|
||||||
>
|
>
|
||||||
> 另外需要注意的是通过`count`属性返回的字符数量并不总是与包含相同字符的`NSString`的`length`属性相同。`NSString`的`length`属性是利用 UTF-16 表示的十六位代码单元数字,而不是 Unicode 可扩展的字符群集。
|
> 另外需要注意的是通过 `count` 属性返回的字符数量并不总是与包含相同字符的 `NSString` 的 `length` 属性相同。`NSString` 的 `length` 属性是利用 UTF-16 表示的十六位代码单元数字,而不是 Unicode 可扩展的字符群集。
|
||||||
|
|
||||||
<a name="accessing_and_modifying_a_string"></a>
|
<a name="accessing_and_modifying_a_string"></a>
|
||||||
## 访问和修改字符串
|
## 访问和修改字符串
|
||||||
@ -422,11 +422,11 @@ print("the number of characters in \(word) is \(word.count)")
|
|||||||
<a name="string_indices"></a>
|
<a name="string_indices"></a>
|
||||||
### 字符串索引
|
### 字符串索引
|
||||||
|
|
||||||
每一个`String`值都有一个关联的索引(*index*)类型,`String.Index`,它对应着字符串中的每一个`Character`的位置。
|
每一个 `String` 值都有一个关联的索引(*index*)类型,`String.Index`,它对应着字符串中的每一个 `Character` 的位置。
|
||||||
|
|
||||||
前面提到,不同的字符可能会占用不同数量的内存空间,所以要知道`Character`的确定位置,就必须从`String`开头遍历每一个 Unicode 标量直到结尾。因此,Swift 的字符串不能用整数(integer)做索引。
|
前面提到,不同的字符可能会占用不同数量的内存空间,所以要知道 `Character` 的确定位置,就必须从 `String` 开头遍历每一个 Unicode 标量直到结尾。因此,Swift 的字符串不能用整数(integer)做索引。
|
||||||
|
|
||||||
使用`startIndex`属性可以获取一个`String`的第一个`Character`的索引。使用`endIndex`属性可以获取最后一个`Character`的后一个位置的索引。因此,`endIndex`属性不能作为一个字符串的有效下标。如果`String`是空串,`startIndex`和`endIndex`是相等的。
|
使用 `startIndex` 属性可以获取一个 `String` 的第一个 `Character` 的索引。使用 `endIndex` 属性可以获取最后一个 `Character` 的后一个位置的索引。因此,`endIndex` 属性不能作为一个字符串的有效下标。如果 `String` 是空串,`startIndex` 和 `endIndex` 是相等的。
|
||||||
|
|
||||||
通过调用 `String` 的 `index(before:)` 或 `index(after:)` 方法,可以立即得到前面或后面的一个索引。您还可以通过调用 `index(_:offsetBy:)` 方法来获取对应偏移量的索引,这种方式可以避免多次调用 `index(before:)` 或 `index(after:)` 方法。
|
通过调用 `String` 的 `index(before:)` 或 `index(after:)` 方法,可以立即得到前面或后面的一个索引。您还可以通过调用 `index(_:offsetBy:)` 方法来获取对应偏移量的索引,这种方式可以避免多次调用 `index(before:)` 或 `index(after:)` 方法。
|
||||||
|
|
||||||
@ -463,7 +463,7 @@ for index in greeting.indices {
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 您可以使用 `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>
|
||||||
### 插入和删除
|
### 插入和删除
|
||||||
@ -540,7 +540,7 @@ if quotation == sameQuotation {
|
|||||||
|
|
||||||
如果两个字符串(或者两个字符)的可扩展的字形群集是标准相等的,那就认为它们是相等的。在这个情况下,即使可扩展的字形群集是有不同的 Unicode 标量构成的,只要它们有同样的语言意义和外观,就认为它们标准相等。
|
如果两个字符串(或者两个字符)的可扩展的字形群集是标准相等的,那就认为它们是相等的。在这个情况下,即使可扩展的字形群集是有不同的 Unicode 标量构成的,只要它们有同样的语言意义和外观,就认为它们标准相等。
|
||||||
|
|
||||||
例如,`LATIN SMALL LETTER E WITH ACUTE`(`U+00E9`)就是标准相等于`LATIN SMALL LETTER E`(`U+0065`)后面加上`COMBINING ACUTE ACCENT`(`U+0301`)。这两个字符群集都是表示字符`é`的有效方式,所以它们被认为是标准相等的:
|
例如,`LATIN SMALL LETTER E WITH ACUTE`(`U+00E9`)就是标准相等于 `LATIN SMALL LETTER E`(`U+0065`)后面加上 `COMBINING ACUTE ACCENT`(`U+0301`)。这两个字符群集都是表示字符 `é` 的有效方式,所以它们被认为是标准相等的:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
// "Voulez-vous un café?" 使用 LATIN SMALL LETTER E WITH ACUTE
|
// "Voulez-vous un café?" 使用 LATIN SMALL LETTER E WITH ACUTE
|
||||||
@ -555,7 +555,7 @@ if eAcuteQuestion == combinedEAcuteQuestion {
|
|||||||
// 打印输出 "These two strings are considered equal"
|
// 打印输出 "These two strings are considered equal"
|
||||||
```
|
```
|
||||||
|
|
||||||
相反,英语中的`LATIN CAPITAL LETTER A`(`U+0041`,或者`A`)不等于俄语中的`CYRILLIC CAPITAL LETTER A`(`U+0410`,或者`A`)。两个字符看着是一样的,但却有不同的语言意义:
|
相反,英语中的 `LATIN CAPITAL LETTER A`(`U+0041`,或者 `A`)不等于俄语中的 `CYRILLIC CAPITAL LETTER A`(`U+0410`,或者 `A`)。两个字符看着是一样的,但却有不同的语言意义:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let latinCapitalLetterA: Character = "\u{41}"
|
let latinCapitalLetterA: Character = "\u{41}"
|
||||||
@ -575,7 +575,7 @@ if latinCapitalLetterA != cyrillicCapitalLetterA {
|
|||||||
<a name="prefix_and_suffix_equality"></a>
|
<a name="prefix_and_suffix_equality"></a>
|
||||||
### 前缀/后缀相等
|
### 前缀/后缀相等
|
||||||
|
|
||||||
通过调用字符串的`hasPrefix(_:)`/`hasSuffix(_:)`方法来检查字符串是否拥有特定前缀/后缀,两个方法均接收一个`String`类型的参数,并返回一个布尔值。
|
通过调用字符串的 `hasPrefix(_:)`/`hasSuffix(_:)` 方法来检查字符串是否拥有特定前缀/后缀,两个方法均接收一个 `String` 类型的参数,并返回一个布尔值。
|
||||||
|
|
||||||
下面的例子以一个字符串数组表示莎士比亚话剧《罗密欧与朱丽叶》中前两场的场景位置:
|
下面的例子以一个字符串数组表示莎士比亚话剧《罗密欧与朱丽叶》中前两场的场景位置:
|
||||||
|
|
||||||
@ -595,7 +595,7 @@ let romeoAndJuliet = [
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
您可以调用`hasPrefix(_:)`方法来计算话剧中第一幕的场景数:
|
您可以调用 `hasPrefix(_:)` 方法来计算话剧中第一幕的场景数:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var act1SceneCount = 0
|
var act1SceneCount = 0
|
||||||
@ -608,7 +608,7 @@ print("There are \(act1SceneCount) scenes in Act 1")
|
|||||||
// 打印输出 "There are 5 scenes in Act 1"
|
// 打印输出 "There are 5 scenes in Act 1"
|
||||||
```
|
```
|
||||||
|
|
||||||
相似地,您可以用`hasSuffix(_:)`方法来计算发生在不同地方的场景数:
|
相似地,您可以用 `hasSuffix(_:)` 方法来计算发生在不同地方的场景数:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var mansionCount = 0
|
var mansionCount = 0
|
||||||
@ -626,24 +626,24 @@ print("\(mansionCount) mansion scenes; \(cellCount) 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>
|
||||||
## 字符串的 Unicode 表示形式
|
## 字符串的 Unicode 表示形式
|
||||||
|
|
||||||
当一个 Unicode 字符串被写进文本文件或者其他储存时,字符串中的 Unicode 标量会用 Unicode 定义的几种`编码格式`(encoding forms)编码。每一个字符串中的小块编码都被称`代码单元`(code units)。这些包括 UTF-8 编码格式(编码字符串为8位的代码单元), UTF-16 编码格式(编码字符串位16位的代码单元),以及 UTF-32 编码格式(编码字符串32位的代码单元)。
|
当一个 Unicode 字符串被写进文本文件或者其他储存时,字符串中的 Unicode 标量会用 Unicode 定义的几种 `编码格式`(encoding forms)编码。每一个字符串中的小块编码都被称 `代码单元`(code units)。这些包括 UTF-8 编码格式(编码字符串为8位的代码单元), UTF-16 编码格式(编码字符串位16位的代码单元),以及 UTF-32 编码格式(编码字符串32位的代码单元)。
|
||||||
|
|
||||||
Swift 提供了几种不同的方式来访问字符串的 Unicode 表示形式。
|
Swift 提供了几种不同的方式来访问字符串的 Unicode 表示形式。
|
||||||
您可以利用`for-in`来对字符串进行遍历,从而以 Unicode 可扩展的字符群集的方式访问每一个`Character`值。
|
您可以利用 `for-in` 来对字符串进行遍历,从而以 Unicode 可扩展的字符群集的方式访问每一个 `Character` 值。
|
||||||
该过程在 [使用字符](#working_with_characters) 中进行了描述。
|
该过程在 [使用字符](#working_with_characters) 中进行了描述。
|
||||||
|
|
||||||
另外,能够以其他三种 Unicode 兼容的方式访问字符串的值:
|
另外,能够以其他三种 Unicode 兼容的方式访问字符串的值:
|
||||||
|
|
||||||
* UTF-8 代码单元集合 (利用字符串的`utf8`属性进行访问)
|
* UTF-8 代码单元集合 (利用字符串的 `utf8` 属性进行访问)
|
||||||
* UTF-16 代码单元集合 (利用字符串的`utf16`属性进行访问)
|
* UTF-16 代码单元集合 (利用字符串的 `utf16` 属性进行访问)
|
||||||
* 21位的 Unicode 标量值集合,也就是字符串的 UTF-32 编码格式 (利用字符串的`unicodeScalars`属性进行访问)
|
* 21位的 Unicode 标量值集合,也就是字符串的 UTF-32 编码格式 (利用字符串的 `unicodeScalars` 属性进行访问)
|
||||||
|
|
||||||
下面由`D`,`o`,`g`,`‼`(`DOUBLE EXCLAMATION MARK`, Unicode 标量 `U+203C`)和`🐶`(`DOG FACE`,Unicode 标量为`U+1F436`)组成的字符串中的每一个字符代表着一种不同的表示:
|
下面由 `D`,`o`,`g`,`‼`(`DOUBLE EXCLAMATION MARK`, Unicode 标量 `U+203C`)和 `🐶`(`DOG FACE`,Unicode 标量为 `U+1F436`)组成的字符串中的每一个字符代表着一种不同的表示:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let dogString = "Dog‼🐶"
|
let dogString = "Dog‼🐶"
|
||||||
@ -652,8 +652,8 @@ let dogString = "Dog‼🐶"
|
|||||||
<a name="UTF-8_representation"></a>
|
<a name="UTF-8_representation"></a>
|
||||||
### UTF-8 表示
|
### UTF-8 表示
|
||||||
|
|
||||||
您可以通过遍历`String`的`utf8`属性来访问它的`UTF-8`表示。
|
您可以通过遍历 `String` 的 `utf8` 属性来访问它的 `UTF-8` 表示。
|
||||||
其为`String.UTF8View`类型的属性,`UTF8View`是无符号8位 (`UInt8`) 值的集合,每一个`UInt8`值都是一个字符的 UTF-8 表示:
|
其为 `String.UTF8View` 类型的属性,`UTF8View` 是无符号8位 (`UInt8`) 值的集合,每一个 `UInt8` 值都是一个字符的 UTF-8 表示:
|
||||||
|
|
||||||
<table style='text-align:center'>
|
<table style='text-align:center'>
|
||||||
<tr height="77">
|
<tr height="77">
|
||||||
@ -700,15 +700,15 @@ print("")
|
|||||||
// 68 111 103 226 128 188 240 159 144 182
|
// 68 111 103 226 128 188 240 159 144 182
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的例子中,前三个10进制`codeUnit`值 (`68`, `111`, `103`) 代表了字符`D`、`o`和 `g`,它们的 UTF-8 表示与 ASCII 表示相同。
|
上面的例子中,前三个10进制 `codeUnit` 值 (`68`, `111`, `103`) 代表了字符 `D`、`o` 和 `g`,它们的 UTF-8 表示与 ASCII 表示相同。
|
||||||
接下来的三个10进制`codeUnit`值 (`226`, `128`, `188`) 是`DOUBLE EXCLAMATION MARK`的3字节 UTF-8 表示。
|
接下来的三个10进制 `codeUnit` 值 (`226`, `128`, `188`) 是 `DOUBLE EXCLAMATION MARK` 的3字节 UTF-8 表示。
|
||||||
最后的四个`codeUnit`值 (`240`, `159`, `144`, `182`) 是`DOG FACE`的4字节 UTF-8 表示。
|
最后的四个 `codeUnit` 值 (`240`, `159`, `144`, `182`) 是 `DOG FACE` 的4字节 UTF-8 表示。
|
||||||
|
|
||||||
<a name="UTF-16_representation"></a>
|
<a name="UTF-16_representation"></a>
|
||||||
### UTF-16 表示
|
### UTF-16 表示
|
||||||
|
|
||||||
您可以通过遍历`String`的`utf16`属性来访问它的`UTF-16`表示。
|
您可以通过遍历 `String` 的 `utf16` 属性来访问它的 `UTF-16` 表示。
|
||||||
其为`String.UTF16View`类型的属性,`UTF16View`是无符号16位 (`UInt16`) 值的集合,每一个`UInt16`都是一个字符的 UTF-16 表示:
|
其为 `String.UTF16View` 类型的属性,`UTF16View` 是无符号16位 (`UInt16`) 值的集合,每一个 `UInt16` 都是一个字符的 UTF-16 表示:
|
||||||
|
|
||||||
<table style='text-align:center'>
|
<table style='text-align:center'>
|
||||||
<tr height="77">
|
<tr height="77">
|
||||||
@ -747,21 +747,21 @@ print("")
|
|||||||
// 68 111 103 8252 55357 56374
|
// 68 111 103 8252 55357 56374
|
||||||
```
|
```
|
||||||
|
|
||||||
同样,前三个`codeUnit`值 (`68`, `111`, `103`) 代表了字符`D`、`o`和`g`,它们的 UTF-16 代码单元和 UTF-8 完全相同(因为这些 Unicode 标量表示 ASCII 字符)。
|
同样,前三个 `codeUnit` 值 (`68`, `111`, `103`) 代表了字符 `D`、`o` 和 `g`,它们的 UTF-16 代码单元和 UTF-8 完全相同(因为这些 Unicode 标量表示 ASCII 字符)。
|
||||||
|
|
||||||
第四个`codeUnit`值 (`8252`) 是一个等于十六进制`203C`的的十进制值。这个代表了`DOUBLE EXCLAMATION MARK`字符的 Unicode 标量值`U+203C`。这个字符在 UTF-16 中可以用一个代码单元表示。
|
第四个 `codeUnit` 值 (`8252`) 是一个等于十六进制 `203C` 的的十进制值。这个代表了 `DOUBLE EXCLAMATION MARK` 字符的 Unicode 标量值 `U+203C`。这个字符在 UTF-16 中可以用一个代码单元表示。
|
||||||
|
|
||||||
第五和第六个`codeUnit`值 (`55357`和`56374`) 是`DOG FACE`字符的 UTF-16 表示。
|
第五和第六个 `codeUnit` 值 (`55357` 和 `56374`) 是 `DOG FACE` 字符的 UTF-16 表示。
|
||||||
第一个值为`U+D83D`(十进制值为`55357`),第二个值为`U+DC36`(十进制值为`56374`)。
|
第一个值为 `U+D83D`(十进制值为 `55357`),第二个值为 `U+DC36`(十进制值为 `56374`)。
|
||||||
|
|
||||||
<a name="unicode_scalars_representation"></a>
|
<a name="unicode_scalars_representation"></a>
|
||||||
### Unicode 标量表示
|
### Unicode 标量表示
|
||||||
|
|
||||||
您可以通过遍历`String`值的`unicodeScalars`属性来访问它的 Unicode 标量表示。
|
您可以通过遍历 `String` 值的 `unicodeScalars` 属性来访问它的 Unicode 标量表示。
|
||||||
其为`UnicodeScalarView`类型的属性,`UnicodeScalarView`是`UnicodeScalar`类型的值的集合。
|
其为 `UnicodeScalarView` 类型的属性,`UnicodeScalarView` 是 `UnicodeScalar` 类型的值的集合。
|
||||||
`UnicodeScalar`是21位的 Unicode 代码点。
|
`UnicodeScalar` 是21位的 Unicode 代码点。
|
||||||
|
|
||||||
每一个`UnicodeScalar`拥有一个`value`属性,可以返回对应的21位数值,用`UInt32`来表示:
|
每一个 `UnicodeScalar` 拥有一个 `value` 属性,可以返回对应的21位数值,用 `UInt32` 来表示:
|
||||||
|
|
||||||
<table style='text-align:center'>
|
<table style='text-align:center'>
|
||||||
<tr height="77">
|
<tr height="77">
|
||||||
@ -798,13 +798,13 @@ print("")
|
|||||||
// 68 111 103 8252 128054
|
// 68 111 103 8252 128054
|
||||||
```
|
```
|
||||||
|
|
||||||
前三个`UnicodeScalar`值(`68`, `111`, `103`)的`value`属性仍然代表字符`D`、`o`和`g`。
|
前三个 `UnicodeScalar` 值(`68`, `111`, `103`)的 `value` 属性仍然代表字符 `D`、`o` 和 `g`。
|
||||||
|
|
||||||
第四个`codeUnit`值(`8252`)仍然是一个等于十六进制`203C`的十进制值。这个代表了`DOUBLE EXCLAMATION MARK`字符的 Unicode 标量`U+203C`。
|
第四个 `codeUnit` 值(`8252`)仍然是一个等于十六进制 `203C` 的十进制值。这个代表了 `DOUBLE EXCLAMATION MARK` 字符的 Unicode 标量 `U+203C`。
|
||||||
|
|
||||||
第五个`UnicodeScalar`值的`value`属性,`128054`,是一个十六进制`1F436`的十进制表示。其等同于`DOG FACE`的 Unicode 标量`U+1F436`。
|
第五个 `UnicodeScalar` 值的 `value` 属性,`128054`,是一个十六进制 `1F436` 的十进制表示。其等同于 `DOG FACE` 的 Unicode 标量 `U+1F436`。
|
||||||
|
|
||||||
作为查询它们的`value`属性的一种替代方法,每个`UnicodeScalar`值也可以用来构建一个新的`String`值,比如在字符串插值中使用:
|
作为查询它们的 `value` 属性的一种替代方法,每个 `UnicodeScalar` 值也可以用来构建一个新的 `String` 值,比如在字符串插值中使用:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
for scalar in dogString.unicodeScalars {
|
for scalar in dogString.unicodeScalars {
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
> 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.1,shanks,2016-11-12
|
> 3.0.1,shanks,2016-11-12
|
||||||
@ -29,20 +29,20 @@
|
|||||||
- [集合操作](#performing_set_operations)
|
- [集合操作](#performing_set_operations)
|
||||||
- [字典](#dictionaries)
|
- [字典](#dictionaries)
|
||||||
|
|
||||||
Swift 语言提供`Arrays`、`Sets`和`Dictionaries`三种基本的*集合类型*用来存储集合数据。数组(Arrays)是有序数据的集。集合(Sets)是无序无重复数据的集。字典(Dictionaries)是无序的键值对的集。
|
Swift 语言提供 `Arrays`、`Sets` 和 `Dictionaries` 三种基本的*集合类型*用来存储集合数据。数组(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>
|
||||||
## 集合的可变性
|
## 集合的可变性
|
||||||
|
|
||||||
如果创建一个`Arrays`、`Sets`或`Dictionaries`并且把它分配成一个变量,这个集合将会是*可变的*。这意味着你可以在创建之后添加更多或移除已存在的数据项,或者改变集合中的数据项。如果我们把`Arrays`、`Sets`或`Dictionaries`分配成常量,那么它就是*不可变的*,它的大小和内容都不能被改变。
|
如果创建一个 `Arrays`、`Sets` 或 `Dictionaries` 并且把它分配成一个变量,这个集合将会是*可变的*。这意味着你可以在创建之后添加更多或移除已存在的数据项,或者改变集合中的数据项。如果我们把 `Arrays`、`Sets` 或 `Dictionaries` 分配成常量,那么它就是*不可变的*,它的大小和内容都不能被改变。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
@ -55,12 +55,12 @@ Swift 语言中的`Arrays`、`Sets`和`Dictionaries`中存储的数据值类型
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> Swift 的`Array`类型被桥接到`Foundation`中的`NSArray`类。更多关于在`Foundation`和`Cocoa`中使用`Array`的信息,参见 [*Using Swift with Cocoa and Obejective-C(Swift 4.1)*](https://developer.apple.com/library/content/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)部分。
|
> Swift 的 `Array` 类型被桥接到 `Foundation` 中的 `NSArray` 类。更多关于在 `Foundation` 和 `Cocoa` 中使用 `Array` 的信息,参见 [*Using Swift with Cocoa and Obejective-C(Swift 4.1)*](https://developer.apple.com/library/content/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="array_type_shorthand_syntax"></a>
|
<a name="array_type_shorthand_syntax"></a>
|
||||||
### 数组的简单语法
|
### 数组的简单语法
|
||||||
|
|
||||||
写 Swift 数组应该遵循像`Array<Element>`这样的形式,其中`Element`是这个数组中唯一允许存在的数据类型。我们也可以使用像`[Element]`这样的简单语法。尽管两种形式在功能上是一样的,但是推荐较短的那种,而且在本文中都会使用这种形式来使用数组。
|
写 Swift 数组应该遵循像 `Array<Element>` 这样的形式,其中 `Element` 是这个数组中唯一允许存在的数据类型。我们也可以使用像 `[Element]` 这样的简单语法。尽管两种形式在功能上是一样的,但是推荐较短的那种,而且在本文中都会使用这种形式来使用数组。
|
||||||
|
|
||||||
<a name="creating_an_empty_array"></a>
|
<a name="creating_an_empty_array"></a>
|
||||||
### 创建一个空数组
|
### 创建一个空数组
|
||||||
@ -73,7 +73,7 @@ print("someInts is of type [Int] with \(someInts.count) items.")
|
|||||||
// 打印 "someInts is of type [Int] with 0 items."
|
// 打印 "someInts is of type [Int] with 0 items."
|
||||||
```
|
```
|
||||||
|
|
||||||
注意,通过构造函数的类型,`someInts`的值类型被推断为`[Int]`。
|
注意,通过构造函数的类型,`someInts` 的值类型被推断为 `[Int]`。
|
||||||
|
|
||||||
或者,如果代码上下文中已经提供了类型信息,例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:`[]`(一对空方括号):
|
或者,如果代码上下文中已经提供了类型信息,例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:`[]`(一对空方括号):
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ someInts = []
|
|||||||
<a name="creating_an_array_with_a_default_value"></a>
|
<a name="creating_an_array_with_a_default_value"></a>
|
||||||
### 创建一个带有默认值的数组
|
### 创建一个带有默认值的数组
|
||||||
|
|
||||||
Swift 中的`Array`类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量(`count`)和适当类型的初始值(`repeating`)传入数组构造函数:
|
Swift 中的 `Array` 类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量(`count`)和适当类型的初始值(`repeating`)传入数组构造函数:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var threeDoubles = Array(repeating: 0.0, count: 3)
|
var threeDoubles = Array(repeating: 0.0, count: 3)
|
||||||
@ -114,42 +114,42 @@ var sixDoubles = threeDoubles + anotherThreeDoubles
|
|||||||
|
|
||||||
`[value 1, value 2, value 3]`。
|
`[value 1, value 2, value 3]`。
|
||||||
|
|
||||||
下面这个例子创建了一个叫做`shoppingList`并且存储`String`的数组:
|
下面这个例子创建了一个叫做 `shoppingList` 并且存储 `String` 的数组:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var shoppingList: [String] = ["Eggs", "Milk"]
|
var shoppingList: [String] = ["Eggs", "Milk"]
|
||||||
// shoppingList 已经被构造并且拥有两个初始项。
|
// shoppingList 已经被构造并且拥有两个初始项。
|
||||||
```
|
```
|
||||||
|
|
||||||
`shoppingList`变量被声明为“字符串值类型的数组“,记作`[String]`。 因为这个数组被规定只有`String`一种数据结构,所以只有`String`类型可以在其中被存取。 在这里,`shoppingList`数组由两个`String`值(`"Eggs"` 和`"Milk"`)构造,并且由数组字面量定义。
|
`shoppingList` 变量被声明为“字符串值类型的数组“,记作 `[String]`。 因为这个数组被规定只有 `String` 一种数据结构,所以只有 `String` 类型可以在其中被存取。 在这里,`shoppingList` 数组由两个 `String` 值(`"Eggs"` 和 `"Milk"`)构造,并且由数组字面量定义。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> `shoppingList`数组被声明为变量(`var`关键字创建)而不是常量(`let`创建)是因为以后可能会有更多的数据项被插入其中。
|
> `shoppingList` 数组被声明为变量(`var` 关键字创建)而不是常量(`let` 创建)是因为以后可能会有更多的数据项被插入其中。
|
||||||
|
|
||||||
在这个例子中,字面量仅仅包含两个`String`值。匹配了该数组的变量声明(只能包含`String`的数组),所以这个字面量的分配过程可以作为用两个初始项来构造`shoppingList`的一种方式。
|
在这个例子中,字面量仅仅包含两个 `String` 值。匹配了该数组的变量声明(只能包含 `String` 的数组),所以这个字面量的分配过程可以作为用两个初始项来构造 `shoppingList` 的一种方式。
|
||||||
|
|
||||||
由于 Swift 的类型推断机制,当我们用字面量构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。 `shoppingList`的构造也可以这样写:
|
由于 Swift 的类型推断机制,当我们用字面量构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。`shoppingList` 的构造也可以这样写:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var shoppingList = ["Eggs", "Milk"]
|
var shoppingList = ["Eggs", "Milk"]
|
||||||
```
|
```
|
||||||
|
|
||||||
因为所有数组字面量中的值都是相同的类型,Swift 可以推断出`[String]`是`shoppingList`中变量的正确类型。
|
因为所有数组字面量中的值都是相同的类型,Swift 可以推断出 `[String]` 是 `shoppingList` 中变量的正确类型。
|
||||||
|
|
||||||
<a name="accessing_and_modifying_an_array"></a>
|
<a name="accessing_and_modifying_an_array"></a>
|
||||||
### 访问和修改数组
|
### 访问和修改数组
|
||||||
|
|
||||||
我们可以通过数组的方法和属性来访问和修改数组,或者使用下标语法。
|
我们可以通过数组的方法和属性来访问和修改数组,或者使用下标语法。
|
||||||
|
|
||||||
可以使用数组的只读属性`count`来获取数组中的数据项数量:
|
可以使用数组的只读属性 `count` 来获取数组中的数据项数量:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
print("The shopping list contains \(shoppingList.count) items.")
|
print("The shopping list contains \(shoppingList.count) items.")
|
||||||
// 输出 "The shopping list contains 2 items."(这个数组有2个项)
|
// 输出 "The shopping list contains 2 items."(这个数组有2个项)
|
||||||
```
|
```
|
||||||
|
|
||||||
使用布尔属性`isEmpty`作为一个缩写形式去检查`count`属性是否为`0`:
|
使用布尔属性 `isEmpty` 作为一个缩写形式去检查 `count` 属性是否为 `0`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if shoppingList.isEmpty {
|
if shoppingList.isEmpty {
|
||||||
@ -160,7 +160,7 @@ if shoppingList.isEmpty {
|
|||||||
// 打印 "The shopping list is not empty."(shoppinglist 不是空的)
|
// 打印 "The shopping list is not empty."(shoppinglist 不是空的)
|
||||||
```
|
```
|
||||||
|
|
||||||
也可以使用`append(_:)`方法在数组后面添加新的数据项:
|
也可以使用 `append(_:)` 方法在数组后面添加新的数据项:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
shoppingList.append("Flour")
|
shoppingList.append("Flour")
|
||||||
@ -185,7 +185,7 @@ var firstItem = shoppingList[0]
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 第一项在数组中的索引值是`0`而不是`1`。 Swift 中的数组索引总是从零开始。
|
> 第一项在数组中的索引值是 `0` 而不是 `1`。 Swift 中的数组索引总是从零开始。
|
||||||
|
|
||||||
我们也可以用下标来改变某个已有索引值对应的数据值:
|
我们也可以用下标来改变某个已有索引值对应的数据值:
|
||||||
|
|
||||||
@ -194,7 +194,7 @@ shoppingList[0] = "Six eggs"
|
|||||||
// 其中的第一项现在是 "Six eggs" 而不是 "Eggs"
|
// 其中的第一项现在是 "Six eggs" 而不是 "Eggs"
|
||||||
```
|
```
|
||||||
|
|
||||||
还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把`"Chocolate Spread"`,`"Cheese"`,和`"Butter"`替换为`"Bananas"`和 `"Apples"`:
|
还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把 `"Chocolate Spread"`,`"Cheese"`,和 `"Butter"` 替换为 `"Bananas"` 和 `"Apples"`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
shoppingList[4...6] = ["Bananas", "Apples"]
|
shoppingList[4...6] = ["Bananas", "Apples"]
|
||||||
@ -205,7 +205,7 @@ shoppingList[4...6] = ["Bananas", "Apples"]
|
|||||||
>
|
>
|
||||||
> 不可以用下标访问的形式去在数组尾部添加新项。
|
> 不可以用下标访问的形式去在数组尾部添加新项。
|
||||||
|
|
||||||
调用数组的`insert(_:at:)`方法来在某个具体索引值之前添加数据项:
|
调用数组的 `insert(_:at:)` 方法来在某个具体索引值之前添加数据项:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
shoppingList.insert("Maple Syrup", at: 0)
|
shoppingList.insert("Maple Syrup", at: 0)
|
||||||
@ -213,9 +213,9 @@ shoppingList.insert("Maple Syrup", at: 0)
|
|||||||
// "Maple Syrup" 现在是这个列表中的第一项
|
// "Maple Syrup" 现在是这个列表中的第一项
|
||||||
```
|
```
|
||||||
|
|
||||||
这次`insert(_:at:)`方法调用把值为`"Maple Syrup"`的新数据项插入列表的最开始位置,并且使用`0`作为索引值。
|
这次 `insert(_:at:)` 方法调用把值为 `"Maple Syrup"` 的新数据项插入列表的最开始位置,并且使用 `0` 作为索引值。
|
||||||
|
|
||||||
类似的我们可以使用`remove(at:)`方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(我们不需要的时候就可以无视它):
|
类似的我们可以使用 `remove(at:)` 方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(我们不需要的时候就可以无视它):
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let mapleSyrup = shoppingList.remove(at: 0)
|
let mapleSyrup = shoppingList.remove(at: 0)
|
||||||
@ -225,16 +225,16 @@ let mapleSyrup = shoppingList.remove(at: 0)
|
|||||||
```
|
```
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 如果我们试着对索引越界的数据进行检索或者设置新值的操作,会引发一个运行期错误。我们可以使用索引值和数组的`count`属性进行比较来在使用某个索引之前先检验是否有效。除了当`count`等于 0 时(说明这是个空数组),最大索引值一直是`count - 1`,因为数组都是零起索引。
|
> 如果我们试着对索引越界的数据进行检索或者设置新值的操作,会引发一个运行期错误。我们可以使用索引值和数组的 `count` 属性进行比较来在使用某个索引之前先检验是否有效。除了当 `count` 等于 0 时(说明这是个空数组),最大索引值一直是 `count - 1`,因为数组都是零起索引。
|
||||||
|
|
||||||
数据项被移除后数组中的空出项会被自动填补,所以现在索引值为`0`的数据项的值再次等于`"Six eggs"`:
|
数据项被移除后数组中的空出项会被自动填补,所以现在索引值为 `0` 的数据项的值再次等于 `"Six eggs"`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
firstItem = shoppingList[0]
|
firstItem = shoppingList[0]
|
||||||
// firstItem 现在等于 "Six eggs"
|
// firstItem 现在等于 "Six eggs"
|
||||||
```
|
```
|
||||||
|
|
||||||
如果我们只想把数组中的最后一项移除,可以使用`removeLast()`方法而不是`remove(at:)`方法来避免我们需要获取数组的`count`属性。就像后者一样,前者也会返回被移除的数据项:
|
如果我们只想把数组中的最后一项移除,可以使用 `removeLast()` 方法而不是 `remove(at:)` 方法来避免我们需要获取数组的 `count` 属性。就像后者一样,前者也会返回被移除的数据项:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let apples = shoppingList.removeLast()
|
let apples = shoppingList.removeLast()
|
||||||
@ -246,7 +246,7 @@ let apples = shoppingList.removeLast()
|
|||||||
<a name="iterating_over_an_array"></a>
|
<a name="iterating_over_an_array"></a>
|
||||||
### 数组的遍历
|
### 数组的遍历
|
||||||
|
|
||||||
我们可以使用`for-in`循环来遍历所有数组中的数据项:
|
我们可以使用 `for-in` 循环来遍历所有数组中的数据项:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
for item in shoppingList {
|
for item in shoppingList {
|
||||||
@ -259,7 +259,7 @@ for item in shoppingList {
|
|||||||
// Bananas
|
// Bananas
|
||||||
```
|
```
|
||||||
|
|
||||||
如果我们同时需要每个数据项的值和索引值,可以使用`enumerated()`方法来进行数组遍历。`enumerated()`返回一个由每一个数据项索引值和数据值组成的元组。我们可以把这个元组分解成临时常量或者变量来进行遍历:
|
如果我们同时需要每个数据项的值和索引值,可以使用 `enumerated()` 方法来进行数组遍历。`enumerated()` 返回一个由每一个数据项索引值和数据值组成的元组。我们可以把这个元组分解成临时常量或者变量来进行遍历:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
for (index, value) in shoppingList. enumerated() {
|
for (index, value) in shoppingList. enumerated() {
|
||||||
@ -272,7 +272,7 @@ for (index, value) in shoppingList. enumerated() {
|
|||||||
// Item 5: Bananas
|
// Item 5: Bananas
|
||||||
```
|
```
|
||||||
|
|
||||||
更多关于`for-in`循环的介绍请参见[for 循环](05_Control_Flow.html#for_loops)。
|
更多关于 `for-in` 循环的介绍请参见[for 循环](05_Control_Flow.html#for_loops)。
|
||||||
|
|
||||||
<a name="sets"></a>
|
<a name="sets"></a>
|
||||||
## 集合(Sets)
|
## 集合(Sets)
|
||||||
@ -280,33 +280,33 @@ 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 4.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 4.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>
|
||||||
#### 集合类型的哈希值
|
#### 集合类型的哈希值
|
||||||
|
|
||||||
一个类型为了存储在集合中,该类型必须是*可哈希化*的--也就是说,该类型必须提供一个方法来计算它的*哈希值*。一个哈希值是`Int`类型的,相等的对象哈希值必须相同,比如`a==b`,因此必须`a.hashValue == b.hashValue`。
|
一个类型为了存储在集合中,该类型必须是*可哈希化*的--也就是说,该类型必须提供一个方法来计算它的*哈希值*。一个哈希值是 `Int` 类型的,相等的对象哈希值必须相同,比如 `a==b`,因此必须 `a.hashValue == b.hashValue`。
|
||||||
|
|
||||||
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` 三个值来说,`==` 的实现必须满足下面三种情况:
|
||||||
|
|
||||||
> * `a == a`(自反性)
|
> * `a == a`(自反性)
|
||||||
> * `a == b`意味着`b == a`(对称性)
|
> * `a == b` 意味着 `b == a`(对称性)
|
||||||
> * `a == b && b == c`意味着`a == c`(传递性)
|
> * `a == b && b == c` 意味着 `a == c`(传递性)
|
||||||
|
|
||||||
关于遵循协议的更多信息,请看[协议](./22_Protocols.html)。
|
关于遵循协议的更多信息,请看[协议](./22_Protocols.html)。
|
||||||
|
|
||||||
<a name="set_type_syntax"></a>
|
<a name="set_type_syntax"></a>
|
||||||
### 集合类型语法
|
### 集合类型语法
|
||||||
|
|
||||||
Swift 中的`Set`类型被写为`Set<Element>`,这里的`Element`表示`Set`中允许存储的类型,和数组不同的是,集合没有等价的简化形式。
|
Swift 中的 `Set` 类型被写为 `Set<Element>`,这里的 `Element` 表示 `Set` 中允许存储的类型,和数组不同的是,集合没有等价的简化形式。
|
||||||
|
|
||||||
<a name="creating_and_initalizing_an_empty_set"></a>
|
<a name="creating_and_initalizing_an_empty_set"></a>
|
||||||
### 创建和构造一个空的集合
|
### 创建和构造一个空的集合
|
||||||
@ -321,9 +321,9 @@ print("letters is of type Set<Character> with \(letters.count) items.")
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 通过构造器,这里的`letters`变量的类型被推断为`Set<Character>`。
|
> 通过构造器,这里的 `letters` 变量的类型被推断为 `Set<Character>`。
|
||||||
|
|
||||||
此外,如果上下文提供了类型信息,比如作为函数的参数或者已知类型的变量或常量,我们可以通过一个空的数组字面量创建一个空的`Set`:
|
此外,如果上下文提供了类型信息,比如作为函数的参数或者已知类型的变量或常量,我们可以通过一个空的数组字面量创建一个空的 `Set`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
letters.insert("a")
|
letters.insert("a")
|
||||||
@ -337,40 +337,40 @@ letters = []
|
|||||||
|
|
||||||
你可以使用数组字面量来构造集合,并且可以使用简化形式写一个或者多个值作为集合元素。
|
你可以使用数组字面量来构造集合,并且可以使用简化形式写一个或者多个值作为集合元素。
|
||||||
|
|
||||||
下面的例子创建一个称之为`favoriteGenres`的集合来存储`String`类型的值:
|
下面的例子创建一个称之为 `favoriteGenres` 的集合来存储 `String` 类型的值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
|
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
|
||||||
// favoriteGenres 被构造成含有三个初始值的集合
|
// favoriteGenres 被构造成含有三个初始值的集合
|
||||||
```
|
```
|
||||||
|
|
||||||
这个`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` 的构造形式可以采用简化的方式代替:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
|
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
|
||||||
```
|
```
|
||||||
|
|
||||||
由于数组字面量中的所有元素类型相同,Swift 可以推断出`Set<String>`作为`favoriteGenres`变量的正确类型。
|
由于数组字面量中的所有元素类型相同,Swift 可以推断出 `Set<String>` 作为 `favoriteGenres` 变量的正确类型。
|
||||||
|
|
||||||
<a name="accesing_and_modifying_a_set"></a>
|
<a name="accesing_and_modifying_a_set"></a>
|
||||||
### 访问和修改一个集合
|
### 访问和修改一个集合
|
||||||
|
|
||||||
你可以通过`Set`的属性和方法来访问和修改一个`Set`。
|
你可以通过 `Set` 的属性和方法来访问和修改一个 `Set`。
|
||||||
|
|
||||||
为了找出一个`Set`中元素的数量,可以使用其只读属性`count`:
|
为了找出一个 `Set` 中元素的数量,可以使用其只读属性 `count`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
print("I have \(favoriteGenres.count) favorite music genres.")
|
print("I have \(favoriteGenres.count) favorite music genres.")
|
||||||
// 打印 "I have 3 favorite music genres."
|
// 打印 "I have 3 favorite music genres."
|
||||||
```
|
```
|
||||||
|
|
||||||
使用布尔属性`isEmpty`作为一个缩写形式去检查`count`属性是否为`0`:
|
使用布尔属性 `isEmpty` 作为一个缩写形式去检查 `count` 属性是否为 `0`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if favoriteGenres.isEmpty {
|
if favoriteGenres.isEmpty {
|
||||||
@ -381,14 +381,14 @@ if favoriteGenres.isEmpty {
|
|||||||
// 打印 "I have particular music preferences."
|
// 打印 "I have particular music preferences."
|
||||||
```
|
```
|
||||||
|
|
||||||
你可以通过调用`Set`的`insert(_:)`方法来添加一个新元素:
|
你可以通过调用 `Set` 的 `insert(_:)` 方法来添加一个新元素:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
favoriteGenres.insert("Jazz")
|
favoriteGenres.insert("Jazz")
|
||||||
// favoriteGenres 现在包含4个元素
|
// favoriteGenres 现在包含4个元素
|
||||||
```
|
```
|
||||||
|
|
||||||
你可以通过调用`Set`的`remove(_:)`方法去删除一个元素,如果该值是该`Set`的一个元素则删除该元素并且返回被删除的元素值,否则如果该`Set`不包含该值,则返回`nil`。另外,`Set`中的所有元素可以通过它的`removeAll()`方法删除。
|
你可以通过调用 `Set` 的 `remove(_:)` 方法去删除一个元素,如果该值是该 `Set` 的一个元素则删除该元素并且返回被删除的元素值,否则如果该 `Set` 不包含该值,则返回 `nil`。另外,`Set` 中的所有元素可以通过它的 `removeAll()` 方法删除。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let removedGenre = favoriteGenres.remove("Rock") {
|
if let removedGenre = favoriteGenres.remove("Rock") {
|
||||||
@ -399,7 +399,7 @@ if let removedGenre = favoriteGenres.remove("Rock") {
|
|||||||
// 打印 "Rock? I'm over it."
|
// 打印 "Rock? I'm over it."
|
||||||
```
|
```
|
||||||
|
|
||||||
使用`contains(_:)`方法去检查`Set`中是否包含一个特定的值:
|
使用 `contains(_:)` 方法去检查 `Set` 中是否包含一个特定的值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if favoriteGenres.contains("Funk") {
|
if favoriteGenres.contains("Funk") {
|
||||||
@ -413,7 +413,7 @@ if favoriteGenres.contains("Funk") {
|
|||||||
<a name="iterating_over_a_set"></a>
|
<a name="iterating_over_a_set"></a>
|
||||||
### 遍历一个集合
|
### 遍历一个集合
|
||||||
|
|
||||||
你可以在一个`for-in`循环中遍历一个`Set`中的所有值。
|
你可以在一个 `for-in` 循环中遍历一个 `Set` 中的所有值。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
for genre in favoriteGenres {
|
for genre in favoriteGenres {
|
||||||
@ -424,9 +424,9 @@ for genre in favoriteGenres {
|
|||||||
// Hip hop
|
// Hip hop
|
||||||
```
|
```
|
||||||
|
|
||||||
更多关于`for-in`循环的信息,参见[For 循环](./05_Control_Flow.html#for_loops)。
|
更多关于 `for-in` 循环的信息,参见[For 循环](./05_Control_Flow.html#for_loops)。
|
||||||
|
|
||||||
Swift 的`Set`类型没有确定的顺序,为了按照特定顺序来遍历一个`Set`中的值可以使用`sorted()`方法,它将返回一个有序数组,这个数组的元素排列顺序由操作符'<'对元素进行比较的结果来确定。
|
Swift 的 `Set` 类型没有确定的顺序,为了按照特定顺序来遍历一个 `Set` 中的值可以使用 `sorted()` 方法,它将返回一个有序数组,这个数组的元素排列顺序由操作符'<'对元素进行比较的结果来确定。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
for genre in favoriteGenres.sorted() {
|
for genre in favoriteGenres.sorted() {
|
||||||
@ -440,19 +440,19 @@ for genre in favoriteGenres.sorted() {
|
|||||||
<a name="performing_set_operations"></a>
|
<a name="performing_set_operations"></a>
|
||||||
## 集合操作
|
## 集合操作
|
||||||
|
|
||||||
你可以高效地完成`Set`的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交。
|
你可以高效地完成 `Set` 的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交。
|
||||||
|
|
||||||
<a name="fundamental_set_operations"></a>
|
<a name="fundamental_set_operations"></a>
|
||||||
### 基本集合操作
|
### 基本集合操作
|
||||||
|
|
||||||
下面的插图描述了两个集合-`a`和`b`-以及通过阴影部分的区域显示集合各种操作的结果。
|
下面的插图描述了两个集合-`a` 和 `b`-以及通过阴影部分的区域显示集合各种操作的结果。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
* 使用`intersection(_:)`方法根据两个集合中都包含的值创建的一个新的集合。
|
* 使用 `intersection(_:)` 方法根据两个集合中都包含的值创建的一个新的集合。
|
||||||
* 使用`symmetricDifference(_:)`方法根据在一个集合中但不在两个集合中的值创建一个新的集合。
|
* 使用 `symmetricDifference(_:)` 方法根据在一个集合中但不在两个集合中的值创建一个新的集合。
|
||||||
* 使用`union(_:)`方法根据两个集合的值创建一个新的集合。
|
* 使用 `union(_:)` 方法根据两个集合的值创建一个新的集合。
|
||||||
* 使用`subtracting(_:)`方法根据不在该集合中的值创建一个新的集合。
|
* 使用 `subtracting(_:)` 方法根据不在该集合中的值创建一个新的集合。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let oddDigits: Set = [1, 3, 5, 7, 9]
|
let oddDigits: Set = [1, 3, 5, 7, 9]
|
||||||
@ -472,15 +472,15 @@ oddDigits. symmetricDifference(singleDigitPrimeNumbers).sorted()
|
|||||||
<a name="set_membership_and_equality"></a>
|
<a name="set_membership_and_equality"></a>
|
||||||
### 集合成员关系和相等
|
### 集合成员关系和相等
|
||||||
|
|
||||||
下面的插图描述了三个集合-`a`,`b`和`c`,以及通过重叠区域表述集合间共享的元素。集合`a`是集合`b`的父集合,因为`a`包含了`b`中所有的元素,相反的,集合`b`是集合`a`的子集合,因为属于`b`的元素也被`a`包含。集合`b`和集合`c`彼此不关联,因为它们之间没有共同的元素。
|
下面的插图描述了三个集合-`a`,`b` 和 `c`,以及通过重叠区域表述集合间共享的元素。集合 `a` 是集合 `b` 的父集合,因为 `a` 包含了 `b` 中所有的元素,相反的,集合 `b` 是集合 `a` 的子集合,因为属于 `b` 的元素也被 `a` 包含。集合 `b` 和集合 `c` 彼此不关联,因为它们之间没有共同的元素。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
* 使用“是否相等”运算符(`==`)来判断两个集合是否包含全部相同的值。
|
* 使用“是否相等”运算符(`==`)来判断两个集合是否包含全部相同的值。
|
||||||
* 使用`isSubset(of:)`方法来判断一个集合中的值是否也被包含在另外一个集合中。
|
* 使用 `isSubset(of:)` 方法来判断一个集合中的值是否也被包含在另外一个集合中。
|
||||||
* 使用`isSuperset(of:)`方法来判断一个集合中包含另一个集合中所有的值。
|
* 使用 `isSuperset(of:)` 方法来判断一个集合中包含另一个集合中所有的值。
|
||||||
* 使用`isStrictSubset(of:)`或者`isStrictSuperset(of:)`方法来判断一个集合是否是另外一个集合的子集合或者父集合并且两个集合并不相等。
|
* 使用 `isStrictSubset(of:)` 或者 `isStrictSuperset(of:)` 方法来判断一个集合是否是另外一个集合的子集合或者父集合并且两个集合并不相等。
|
||||||
* 使用`isDisjoint(with:)`方法来判断两个集合是否不含有相同的值(是否没有交集)。
|
* 使用 `isDisjoint(with:)` 方法来判断两个集合是否不含有相同的值(是否没有交集)。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let houseAnimals: Set = ["🐶", "🐱"]
|
let houseAnimals: Set = ["🐶", "🐱"]
|
||||||
@ -502,20 +502,20 @@ farmAnimals.isDisjoint(with: cityAnimals)
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> Swift 的`Dictionary`类型被桥接到`Foundation`的`NSDictionary`类。
|
> Swift 的 `Dictionary` 类型被桥接到 `Foundation` 的 `NSDictionary` 类。
|
||||||
>
|
>
|
||||||
> 更多关于在`Foundation`和`Cocoa`中使用`Dictionary`类型的信息,参见 [*Using Swift with Cocoa and Obejective-C(Swift 4.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 4.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>
|
||||||
### 字典类型简化语法
|
### 字典类型简化语法
|
||||||
|
|
||||||
Swift 的字典使用`Dictionary<Key, Value>`定义,其中`Key`是字典中键的数据类型,`Value`是字典中对应于这些键所存储值的数据类型。
|
Swift 的字典使用 `Dictionary<Key, Value>` 定义,其中 `Key` 是字典中键的数据类型,`Value` 是字典中对应于这些键所存储值的数据类型。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 一个字典的`Key`类型必须遵循`Hashable`协议,就像`Set`的值类型。
|
> 一个字典的 `Key` 类型必须遵循 `Hashable` 协议,就像 `Set` 的值类型。
|
||||||
|
|
||||||
我们也可以用`[Key: Value]`这样简化的形式去创建一个字典类型。虽然这两种形式功能上相同,但是后者是首选,并且这本指导书涉及到字典类型时通篇采用后者。
|
我们也可以用 `[Key: Value]` 这样简化的形式去创建一个字典类型。虽然这两种形式功能上相同,但是后者是首选,并且这本指导书涉及到字典类型时通篇采用后者。
|
||||||
|
|
||||||
<a name="creating_an_empty_dictionary"></a>
|
<a name="creating_an_empty_dictionary"></a>
|
||||||
### 创建一个空字典
|
### 创建一个空字典
|
||||||
@ -527,9 +527,9 @@ var namesOfIntegers = [Int: String]()
|
|||||||
// namesOfIntegers 是一个空的 [Int: String] 字典
|
// namesOfIntegers 是一个空的 [Int: String] 字典
|
||||||
```
|
```
|
||||||
|
|
||||||
这个例子创建了一个`[Int: String]`类型的空字典来储存整数的英语命名。它的键是`Int`型,值是`String`型。
|
这个例子创建了一个 `[Int: String]` 类型的空字典来储存整数的英语命名。它的键是 `Int` 型,值是 `String` 型。
|
||||||
|
|
||||||
如果上下文已经提供了类型信息,我们可以使用空字典字面量来创建一个空字典,记作`[:]`(中括号中放一个冒号):
|
如果上下文已经提供了类型信息,我们可以使用空字典字面量来创建一个空字典,记作 `[:]`(中括号中放一个冒号):
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
namesOfIntegers[16] = "sixteen"
|
namesOfIntegers[16] = "sixteen"
|
||||||
@ -541,9 +541,9 @@ namesOfIntegers = [:]
|
|||||||
<a name="creating_a_dictionary_with_a_dictionary_literal"></a>
|
<a name="creating_a_dictionary_with_a_dictionary_literal"></a>
|
||||||
## 用字典字面量创建字典
|
## 用字典字面量创建字典
|
||||||
|
|
||||||
我们可以使用*字典字面量*来构造字典,这和我们刚才介绍过的数组字面量拥有相似语法。字典字面量是一种将一个或多个键值对写作`Dictionary`集合的快捷途径。
|
我们可以使用*字典字面量*来构造字典,这和我们刚才介绍过的数组字面量拥有相似语法。字典字面量是一种将一个或多个键值对写作 `Dictionary` 集合的快捷途径。
|
||||||
|
|
||||||
一个键值对是一个`key`和一个`value`的结合体。在字典字面量中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含、由逗号分割:
|
一个键值对是一个 `key` 和一个 `value` 的结合体。在字典字面量中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含、由逗号分割:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
[key 1: value 1, key 2: value 2, key 3: value 3]
|
[key 1: value 1, key 2: value 2, key 3: value 3]
|
||||||
@ -555,38 +555,38 @@ namesOfIntegers = [:]
|
|||||||
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
|
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`。
|
||||||
|
|
||||||
这个字典语句包含了两个`String: String`类型的键值对。它们对应`airports`变量声明的类型(一个只有`String`键和`String`值的字典)所以这个字典字面量的任务是构造拥有两个初始数据项的`airport`字典。
|
这个字典语句包含了两个 `String: String` 类型的键值对。它们对应 `airports` 变量声明的类型(一个只有 `String` 键和 `String` 值的字典)所以这个字典字面量的任务是构造拥有两个初始数据项的 `airport` 字典。
|
||||||
|
|
||||||
和数组一样,我们在用字典字面量构造字典时,如果它的键和值都有各自一致的类型,那么就不必写出字典的类型。
|
和数组一样,我们在用字典字面量构造字典时,如果它的键和值都有各自一致的类型,那么就不必写出字典的类型。
|
||||||
`airports`字典也可以用这种简短方式定义:
|
`airports` 字典也可以用这种简短方式定义:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
|
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
|
||||||
```
|
```
|
||||||
|
|
||||||
因为这个语句中所有的键和值都各自拥有相同的数据类型,Swift 可以推断出`Dictionary<String, String>`是`airports`字典的正确类型。
|
因为这个语句中所有的键和值都各自拥有相同的数据类型,Swift 可以推断出 `Dictionary<String, String>` 是 `airports` 字典的正确类型。
|
||||||
|
|
||||||
<a name="accessing_and_modifying_a_dictionary"></a>
|
<a name="accessing_and_modifying_a_dictionary"></a>
|
||||||
### 访问和修改字典
|
### 访问和修改字典
|
||||||
|
|
||||||
我们可以通过字典的方法和属性来访问和修改字典,或者通过使用下标语法。
|
我们可以通过字典的方法和属性来访问和修改字典,或者通过使用下标语法。
|
||||||
|
|
||||||
和数组一样,我们可以通过字典的只读属性`count`来获取某个字典的数据项数量:
|
和数组一样,我们可以通过字典的只读属性 `count` 来获取某个字典的数据项数量:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
print("The dictionary of airports contains \(airports.count) items.")
|
print("The dictionary of airports contains \(airports.count) items.")
|
||||||
// 打印 "The dictionary of airports contains 2 items."(这个字典有两个数据项)
|
// 打印 "The dictionary of airports contains 2 items."(这个字典有两个数据项)
|
||||||
```
|
```
|
||||||
|
|
||||||
使用布尔属性`isEmpty`作为一个缩写形式去检查`count`属性是否为`0`:
|
使用布尔属性 `isEmpty` 作为一个缩写形式去检查 `count` 属性是否为 `0`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if airports.isEmpty {
|
if airports.isEmpty {
|
||||||
@ -611,11 +611,11 @@ airports["LHR"] = "London Heathrow"
|
|||||||
// "LHR"对应的值 被改为 "London Heathrow
|
// "LHR"对应的值 被改为 "London Heathrow
|
||||||
```
|
```
|
||||||
|
|
||||||
作为另一种下标方法,字典的`updateValue(_:forKey:)`方法可以设置或者更新特定键对应的值。就像上面所示的下标示例,`updateValue(_:forKey:)`方法在这个键不存在对应值的时候会设置新值或者在存在时更新已存在的值。和上面的下标方法不同的,`updateValue(_:forKey:)`这个方法返回更新值之前的原值。这样使得我们可以检查更新是否成功。
|
作为另一种下标方法,字典的 `updateValue(_:forKey:)` 方法可以设置或者更新特定键对应的值。就像上面所示的下标示例,`updateValue(_:forKey:)` 方法在这个键不存在对应值的时候会设置新值或者在存在时更新已存在的值。和上面的下标方法不同的,`updateValue(_:forKey:)` 这个方法返回更新值之前的原值。这样使得我们可以检查更新是否成功。
|
||||||
|
|
||||||
`updateValue(_:forKey:)`方法会返回对应值的类型的可选值。举例来说:对于存储`String`值的字典,这个函数会返回一个`String?`或者“可选 `String`”类型的值。
|
`updateValue(_:forKey:)` 方法会返回对应值的类型的可选值。举例来说:对于存储 `String` 值的字典,这个函数会返回一个 `String?` 或者“可选 `String`”类型的值。
|
||||||
|
|
||||||
如果有值存在于更新前,则这个可选值包含了旧值,否则它将会是`nil`。
|
如果有值存在于更新前,则这个可选值包含了旧值,否则它将会是 `nil`。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
|
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
|
||||||
@ -624,7 +624,7 @@ if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
|
|||||||
// 输出 "The old value for DUB was Dublin."
|
// 输出 "The old value for DUB was Dublin."
|
||||||
```
|
```
|
||||||
|
|
||||||
我们也可以使用下标语法来在字典中检索特定键对应的值。因为有可能请求的键没有对应的值存在,字典的下标访问会返回对应值的类型的可选值。如果这个字典包含请求键所对应的值,下标会返回一个包含这个存在值的可选值,否则将返回`nil`:
|
我们也可以使用下标语法来在字典中检索特定键对应的值。因为有可能请求的键没有对应的值存在,字典的下标访问会返回对应值的类型的可选值。如果这个字典包含请求键所对应的值,下标会返回一个包含这个存在值的可选值,否则将返回 `nil`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let airportName = airports["DUB"] {
|
if let airportName = airports["DUB"] {
|
||||||
@ -635,7 +635,7 @@ if let airportName = airports["DUB"] {
|
|||||||
// 打印 "The name of the airport is Dublin Airport."
|
// 打印 "The name of the airport is Dublin Airport."
|
||||||
```
|
```
|
||||||
|
|
||||||
我们还可以使用下标语法来通过给某个键的对应值赋值为`nil`来从字典里移除一个键值对:
|
我们还可以使用下标语法来通过给某个键的对应值赋值为 `nil` 来从字典里移除一个键值对:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
airports["APL"] = "Apple Internation"
|
airports["APL"] = "Apple Internation"
|
||||||
@ -644,7 +644,7 @@ airports["APL"] = nil
|
|||||||
// APL 现在被移除了
|
// APL 现在被移除了
|
||||||
```
|
```
|
||||||
|
|
||||||
此外,`removeValue(forKey:)`方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的值或者在没有值的情况下返回`nil`:
|
此外,`removeValue(forKey:)` 方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的值或者在没有值的情况下返回 `nil`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let removedValue = airports. removeValue(forKey: "DUB") {
|
if let removedValue = airports. removeValue(forKey: "DUB") {
|
||||||
@ -658,7 +658,7 @@ if let removedValue = airports. removeValue(forKey: "DUB") {
|
|||||||
<a name="iterating_over_a_dictionary"></a>
|
<a name="iterating_over_a_dictionary"></a>
|
||||||
### 字典遍历
|
### 字典遍历
|
||||||
|
|
||||||
我们可以使用`for-in`循环来遍历某个字典中的键值对。每一个字典中的数据项都以`(key, value)`元组形式返回,并且我们可以使用临时常量或者变量来分解这些元组:
|
我们可以使用 `for-in` 循环来遍历某个字典中的键值对。每一个字典中的数据项都以 `(key, value)` 元组形式返回,并且我们可以使用临时常量或者变量来分解这些元组:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
for (airportCode, airportName) in airports {
|
for (airportCode, airportName) in airports {
|
||||||
@ -668,9 +668,9 @@ for (airportCode, airportName) in airports {
|
|||||||
// LHR: London Heathrow
|
// LHR: London Heathrow
|
||||||
```
|
```
|
||||||
|
|
||||||
更多关于`for-in`循环的信息,参见[For 循环](./05_Control_Flow.html#for_loops)。
|
更多关于 `for-in` 循环的信息,参见[For 循环](./05_Control_Flow.html#for_loops)。
|
||||||
|
|
||||||
通过访问`keys`或者`values`属性,我们也可以遍历字典的键或者值:
|
通过访问 `keys` 或者 `values` 属性,我们也可以遍历字典的键或者值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
for airportCode in airports.keys {
|
for airportCode in airports.keys {
|
||||||
@ -686,7 +686,7 @@ for airportName in airports.values {
|
|||||||
// Airport name: London Heathrow
|
// Airport name: London Heathrow
|
||||||
```
|
```
|
||||||
|
|
||||||
如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受`Array`实例的 API 的参数,可以直接使用`keys`或者`values`属性构造一个新数组:
|
如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受 `Array` 实例的 API 的参数,可以直接使用 `keys` 或者 `values` 属性构造一个新数组:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let airportCodes = [String](airports.keys)
|
let airportCodes = [String](airports.keys)
|
||||||
@ -696,4 +696,4 @@ let airportNames = [String](airports.values)
|
|||||||
// airportNames 是 ["Toronto Pearson", "London Heathrow"]
|
// airportNames 是 ["Toronto Pearson", "London Heathrow"]
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift 的字典类型是无序集合类型。为了以特定的顺序遍历字典的键或值,可以对字典的`keys`或`values`属性使用`sorted()`方法。
|
Swift 的字典类型是无序集合类型。为了以特定的顺序遍历字典的键或值,可以对字典的 `keys` 或 `values` 属性使用 `sorted()` 方法。
|
||||||
|
|||||||
@ -38,11 +38,11 @@
|
|||||||
- [提前退出](#early_exit)
|
- [提前退出](#early_exit)
|
||||||
- [检测 API 可用性](#checking_api_availability)
|
- [检测 API 可用性](#checking_api_availability)
|
||||||
|
|
||||||
Swift提供了多种流程控制结构,包括可以多次执行任务的`while`循环,基于特定条件选择执行不同代码分支的`if`、`guard`和`switch`语句,还有控制流程跳转到其他代码位置的`break`和`continue`语句。
|
Swift 提供了多种流程控制结构,包括可以多次执行任务的 `while` 循环,基于特定条件选择执行不同代码分支的 `if`、`guard` 和 `switch` 语句,还有控制流程跳转到其他代码位置的 `break` 和 `continue` 语句。
|
||||||
|
|
||||||
Swift 还提供了`for-in`循环,用来更简单地遍历数组(Array),字典(Dictionary),区间(Range),字符串(String)和其他序列类型。
|
Swift 还提供了 `for-in` 循环,用来更简单地遍历数组(Array),字典(Dictionary),区间(Range),字符串(String)和其他序列类型。
|
||||||
|
|
||||||
Swift 的`switch`语句比 C 语言中更加强大。case 还可以匹配很多不同的模式,包括范围匹配,元组(tuple)和特定类型匹配。`switch`语句的 case 中匹配的值可以声明为临时常量或变量,在 case 作用域内使用,也可以配合`where`来描述更复杂的匹配条件。
|
Swift 的 `switch` 语句比 C 语言中更加强大。case 还可以匹配很多不同的模式,包括范围匹配,元组(tuple)和特定类型匹配。`switch` 语句的 case 中匹配的值可以声明为临时常量或变量,在 case 作用域内使用,也可以配合 `where` 来描述更复杂的匹配条件。
|
||||||
|
|
||||||
<a name="for_in_loops"></a>
|
<a name="for_in_loops"></a>
|
||||||
## For-In 循环
|
## For-In 循环
|
||||||
@ -106,7 +106,7 @@ 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)。
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ for tickMark in 0..<minutes {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
一些用户可能在其UI中可能需要较少的刻度。他们可以每5分钟作为一个刻度。使用 `stride(from:to:by:)` 函数跳过不需要的标记。
|
一些用户可能在其 UI 中可能需要较少的刻度。他们可以每5分钟作为一个刻度。使用 `stride(from:to:by:)` 函数跳过不需要的标记。
|
||||||
|
|
||||||
```
|
```
|
||||||
let minuteInterval = 5
|
let minuteInterval = 5
|
||||||
@ -139,15 +139,15 @@ for tickMark in stride(from: 3, through: hours, by: hourInterval) {
|
|||||||
<a name="while_loops"></a>
|
<a name="while_loops"></a>
|
||||||
## While 循环
|
## While 循环
|
||||||
|
|
||||||
`while`循环会一直运行一段语句直到条件变成`false`。这类循环适合使用在第一次迭代前,迭代次数未知的情况下。Swift 提供两种`while`循环形式:
|
`while` 循环会一直运行一段语句直到条件变成 `false`。这类循环适合使用在第一次迭代前,迭代次数未知的情况下。Swift 提供两种 `while` 循环形式:
|
||||||
|
|
||||||
* `while`循环,每次在循环开始时计算条件是否符合;
|
* `while` 循环,每次在循环开始时计算条件是否符合;
|
||||||
* `repeat-while`循环,每次在循环结束时计算条件是否符合。
|
* `repeat-while` 循环,每次在循环结束时计算条件是否符合。
|
||||||
|
|
||||||
<a name="while"></a>
|
<a name="while"></a>
|
||||||
### While
|
### While
|
||||||
|
|
||||||
`while`循环从计算一个条件开始。如果条件为`true`,会重复运行一段语句,直到条件变为`false`。
|
`while` 循环从计算一个条件开始。如果条件为 `true`,会重复运行一段语句,直到条件变为 `false`。
|
||||||
|
|
||||||
下面是 `while` 循环的一般格式:
|
下面是 `while` 循环的一般格式:
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ while condition {
|
|||||||
* 如果在某轮结束,你移动到了梯子的底部,可以顺着梯子爬上去;
|
* 如果在某轮结束,你移动到了梯子的底部,可以顺着梯子爬上去;
|
||||||
* 如果在某轮结束,你移动到了蛇的头部,你会顺着蛇的身体滑下去。
|
* 如果在某轮结束,你移动到了蛇的头部,你会顺着蛇的身体滑下去。
|
||||||
|
|
||||||
游戏盘面可以使用一个`Int`数组来表达。数组的长度由一个`finalSquare`常量储存,用来初始化数组和检测最终胜利条件。游戏盘面由 26 个 `Int` 0 值初始化,而不是 25 个(由`0`到`25`,一共 26 个):
|
游戏盘面可以使用一个 `Int` 数组来表达。数组的长度由一个 `finalSquare` 常量储存,用来初始化数组和检测最终胜利条件。游戏盘面由 26 个 `Int` 0 值初始化,而不是 25 个(由 `0` 到 `25`,一共 26 个):
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let finalSquare = 25
|
let finalSquare = 25
|
||||||
@ -182,7 +182,7 @@ board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
|
|||||||
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
|
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
|
||||||
```
|
```
|
||||||
|
|
||||||
3 号方格是梯子的底部,会让你向上移动到 11 号方格,我们使用`board[03]`等于`+08`(来表示`11`和`3`之间的差值)。为了对齐语句,这里使用了一元正运算符(`+i`)和一元负运算符(`-i`),并且小于 10 的数字都使用 0 补齐(这些语法的技巧不是必要的,只是为了让代码看起来更加整洁)。
|
3 号方格是梯子的底部,会让你向上移动到 11 号方格,我们使用 `board[03]` 等于 `+08`(来表示 `11` 和 `3` 之间的差值)。为了对齐语句,这里使用了一元正运算符(`+i`)和一元负运算符(`-i`),并且小于 10 的数字都使用 0 补齐(这些语法的技巧不是必要的,只是为了让代码看起来更加整洁)。
|
||||||
|
|
||||||
玩家由左下角空白处编号为 0 的方格开始游戏。玩家第一次掷骰子后才会进入游戏盘面:
|
玩家由左下角空白处编号为 0 的方格开始游戏。玩家第一次掷骰子后才会进入游戏盘面:
|
||||||
|
|
||||||
@ -203,28 +203,28 @@ while square < finalSquare {
|
|||||||
print("Game over!")
|
print("Game over!")
|
||||||
```
|
```
|
||||||
|
|
||||||
本例中使用了最简单的方法来模拟掷骰子。 `diceRoll`的值并不是一个随机数,而是以`0`为初始值,之后每一次`while`循环,`diceRoll`的值增加 1 ,然后检测是否超出了最大值。当`diceRoll`的值等于 7 时,就超过了骰子的最大值,会被重置为`1`。所以`diceRoll`的取值顺序会一直是 `1` ,`2`,`3`,`4`,`5`,`6`,`1`,`2` 等。
|
本例中使用了最简单的方法来模拟掷骰子。`diceRoll` 的值并不是一个随机数,而是以 `0` 为初始值,之后每一次 `while` 循环,`diceRoll` 的值增加 1 ,然后检测是否超出了最大值。当 `diceRoll` 的值等于 7 时,就超过了骰子的最大值,会被重置为 `1`。所以 `diceRoll` 的取值顺序会一直是 `1`,`2`,`3`,`4`,`5`,`6`,`1`,`2` 等。
|
||||||
|
|
||||||
掷完骰子后,玩家向前移动`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`,此时游戏结束。
|
||||||
|
|
||||||
`while` 循环比较适合本例中的这种情况,因为在 `while` 循环开始时,我们并不知道游戏要跑多久,只有在达成指定条件时循环才会结束。
|
`while` 循环比较适合本例中的这种情况,因为在 `while` 循环开始时,我们并不知道游戏要跑多久,只有在达成指定条件时循环才会结束。
|
||||||
|
|
||||||
<a name="repeat_while"></a>
|
<a name="repeat_while"></a>
|
||||||
### Repeat-While
|
### Repeat-While
|
||||||
|
|
||||||
`while`循环的另外一种形式是`repeat-while`,它和`while`的区别是在判断循环条件之前,先执行一次循环的代码块。然后重复循环直到条件为`false`。
|
`while` 循环的另外一种形式是 `repeat-while`,它和 `while` 的区别是在判断循环条件之前,先执行一次循环的代码块。然后重复循环直到条件为 `false`。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> Swift语言的`repeat-while`循环和其他语言中的`do-while`循环是类似的。
|
> Swift 语言的 `repeat-while` 循环和其他语言中的 `do-while` 循环是类似的。
|
||||||
|
|
||||||
下面是 `repeat-while`循环的一般格式:
|
下面是 `repeat-while` 循环的一般格式:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
repeat {
|
repeat {
|
||||||
@ -232,7 +232,7 @@ repeat {
|
|||||||
} while condition
|
} while condition
|
||||||
```
|
```
|
||||||
|
|
||||||
还是*蛇和梯子*的游戏,使用`repeat-while`循环来替代`while`循环。`finalSquare`、`board`、`square`和`diceRoll`的值初始化同`while`循环时一样:
|
还是*蛇和梯子*的游戏,使用 `repeat-while` 循环来替代 `while` 循环。`finalSquare`、`board`、`square` 和 `diceRoll` 的值初始化同 `while` 循环时一样:
|
||||||
|
|
||||||
``` swift
|
``` swift
|
||||||
let finalSquare = 25
|
let finalSquare = 25
|
||||||
@ -243,9 +243,9 @@ var square = 0
|
|||||||
var diceRoll = 0
|
var diceRoll = 0
|
||||||
```
|
```
|
||||||
|
|
||||||
`repeat-while`的循环版本,循环中*第一步*就需要去检测是否在梯子或者蛇的方块上。没有梯子会让玩家直接上到第 25 个方格,所以玩家不会通过梯子直接赢得游戏。这样在循环开始时先检测是否踩在梯子或者蛇上是安全的。
|
`repeat-while` 的循环版本,循环中*第一步*就需要去检测是否在梯子或者蛇的方块上。没有梯子会让玩家直接上到第 25 个方格,所以玩家不会通过梯子直接赢得游戏。这样在循环开始时先检测是否踩在梯子或者蛇上是安全的。
|
||||||
|
|
||||||
游戏开始时,玩家在第 0 个方格上,`board[0]`一直等于 0, 不会有什么影响:
|
游戏开始时,玩家在第 0 个方格上,`board[0]` 一直等于 0, 不会有什么影响:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
repeat {
|
repeat {
|
||||||
@ -260,21 +260,21 @@ repeat {
|
|||||||
print("Game over!")
|
print("Game over!")
|
||||||
```
|
```
|
||||||
|
|
||||||
检测完玩家是否踩在梯子或者蛇上之后,开始掷骰子,然后玩家向前移动`diceRoll`个方格,本轮循环结束。
|
检测完玩家是否踩在梯子或者蛇上之后,开始掷骰子,然后玩家向前移动 `diceRoll` 个方格,本轮循环结束。
|
||||||
|
|
||||||
循环条件(`while square < finalSquare`)和`while`方式相同,但是只会在循环结束后进行计算。在这个游戏中,`repeat-while`表现得比`while`循环更好。`repeat-while`方式会在条件判断`square`没有超出后直接运行`square += board[square]`,这种方式可以比起前面 `while` 循环的版本,可以省去数组越界的检查。
|
循环条件(`while square < finalSquare`)和 `while` 方式相同,但是只会在循环结束后进行计算。在这个游戏中,`repeat-while` 表现得比 `while` 循环更好。`repeat-while` 方式会在条件判断 `square` 没有超出后直接运行 `square += board[square]`,这种方式可以比起前面 `while` 循环的版本,可以省去数组越界的检查。
|
||||||
|
|
||||||
<a name="conditional_statement"></a>
|
<a name="conditional_statement"></a>
|
||||||
## 条件语句
|
## 条件语句
|
||||||
|
|
||||||
根据特定的条件执行特定的代码通常是十分有用的。当错误发生时,你可能想运行额外的代码;或者,当值太大或太小时,向用户显示一条消息。要实现这些功能,你就需要使用*条件语句*。
|
根据特定的条件执行特定的代码通常是十分有用的。当错误发生时,你可能想运行额外的代码;或者,当值太大或太小时,向用户显示一条消息。要实现这些功能,你就需要使用*条件语句*。
|
||||||
|
|
||||||
Swift 提供两种类型的条件语句:`if`语句和`switch`语句。通常,当条件较为简单且可能的情况很少时,使用`if`语句。而`switch`语句更适用于条件较复杂、有更多排列组合的时候。并且`switch`在需要用到模式匹配(pattern-matching)的情况下会更有用。
|
Swift 提供两种类型的条件语句:`if` 语句和 `switch` 语句。通常,当条件较为简单且可能的情况很少时,使用 `if` 语句。而 `switch` 语句更适用于条件较复杂、有更多排列组合的时候。并且 `switch` 在需要用到模式匹配(pattern-matching)的情况下会更有用。
|
||||||
|
|
||||||
<a name="if"></a>
|
<a name="if"></a>
|
||||||
### If
|
### If
|
||||||
|
|
||||||
`if`语句最简单的形式就是只包含一个条件,只有该条件为`true`时,才执行相关代码:
|
`if` 语句最简单的形式就是只包含一个条件,只有该条件为 `true` 时,才执行相关代码:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var temperatureInFahrenheit = 30
|
var temperatureInFahrenheit = 30
|
||||||
@ -284,9 +284,9 @@ if temperatureInFahrenheit <= 32 {
|
|||||||
// 输出 "It's very cold. Consider wearing a scarf."
|
// 输出 "It's very cold. Consider wearing a scarf."
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的例子会判断温度是否小于等于 32 华氏度(水的冰点)。如果是,则打印一条消息;否则,不打印任何消息,继续执行`if`块后面的代码。
|
上面的例子会判断温度是否小于等于 32 华氏度(水的冰点)。如果是,则打印一条消息;否则,不打印任何消息,继续执行 `if` 块后面的代码。
|
||||||
|
|
||||||
当然,`if`语句允许二选一执行,叫做`else`从句。也就是当条件为`false`时,执行 *else 语句*:
|
当然,`if` 语句允许二选一执行,叫做 `else` 从句。也就是当条件为 `false` 时,执行 *else 语句*:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
temperatureInFahrenheit = 40
|
temperatureInFahrenheit = 40
|
||||||
@ -298,9 +298,9 @@ if temperatureInFahrenheit <= 32 {
|
|||||||
// 输出 "It's not that cold. Wear a t-shirt."
|
// 输出 "It's not that cold. Wear a t-shirt."
|
||||||
```
|
```
|
||||||
|
|
||||||
显然,这两条分支中总有一条会被执行。由于温度已升至 40 华氏度,不算太冷,没必要再围围巾。因此,`else`分支就被触发了。
|
显然,这两条分支中总有一条会被执行。由于温度已升至 40 华氏度,不算太冷,没必要再围围巾。因此,`else` 分支就被触发了。
|
||||||
|
|
||||||
你可以把多个`if`语句链接在一起,来实现更多分支:
|
你可以把多个 `if` 语句链接在一起,来实现更多分支:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
temperatureInFahrenheit = 90
|
temperatureInFahrenheit = 90
|
||||||
@ -314,9 +314,9 @@ if temperatureInFahrenheit <= 32 {
|
|||||||
// 输出 "It's really warm. Don't forget to wear sunscreen."
|
// 输出 "It's really warm. Don't forget to wear sunscreen."
|
||||||
```
|
```
|
||||||
|
|
||||||
在上面的例子中,额外的`if`语句用于判断是不是特别热。而最后的`else`语句被保留了下来,用于打印既不冷也不热时的消息。
|
在上面的例子中,额外的 `if` 语句用于判断是不是特别热。而最后的 `else` 语句被保留了下来,用于打印既不冷也不热时的消息。
|
||||||
|
|
||||||
实际上,当不需要完整判断情况的时候,最后的`else`语句是可选的:
|
实际上,当不需要完整判断情况的时候,最后的 `else` 语句是可选的:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
temperatureInFahrenheit = 72
|
temperatureInFahrenheit = 72
|
||||||
@ -327,14 +327,14 @@ if temperatureInFahrenheit <= 32 {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
在这个例子中,由于既不冷也不热,所以不会触发`if`或`else if`分支,也就不会打印任何消息。
|
在这个例子中,由于既不冷也不热,所以不会触发 `if` 或 `else if` 分支,也就不会打印任何消息。
|
||||||
|
|
||||||
<a name="switch"></a>
|
<a name="switch"></a>
|
||||||
### Switch
|
### Switch
|
||||||
|
|
||||||
`switch`语句会尝试把某个值与若干个模式(pattern)进行匹配。根据第一个匹配成功的模式,`switch`语句会执行对应的代码。当有可能的情况较多时,通常用`switch`语句替换`if`语句。
|
`switch` 语句会尝试把某个值与若干个模式(pattern)进行匹配。根据第一个匹配成功的模式,`switch` 语句会执行对应的代码。当有可能的情况较多时,通常用 `switch` 语句替换 `if` 语句。
|
||||||
|
|
||||||
`switch`语句最简单的形式就是把某个值与一个或若干个相同类型的值作比较:
|
`switch` 语句最简单的形式就是把某个值与一个或若干个相同类型的值作比较:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
switch some value to consider {
|
switch some value to consider {
|
||||||
@ -348,13 +348,13 @@ default:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`switch`语句由*多个 case* 构成,每个由`case`关键字开始。为了匹配某些更特定的值,Swift 提供了几种方法来进行更复杂的模式匹配,这些模式将在本节的稍后部分提到。
|
`switch` 语句由*多个 case* 构成,每个由 `case` 关键字开始。为了匹配某些更特定的值,Swift 提供了几种方法来进行更复杂的模式匹配,这些模式将在本节的稍后部分提到。
|
||||||
|
|
||||||
与`if`语句类似,每一个 case 都是代码执行的一条分支。`switch`语句会决定哪一条分支应该被执行,这个流程被称作根据给定的值*切换(switching)*。
|
与 `if` 语句类似,每一个 case 都是代码执行的一条分支。`switch` 语句会决定哪一条分支应该被执行,这个流程被称作根据给定的值*切换(switching)*。
|
||||||
|
|
||||||
`switch`语句必须是完备的。这就是说,每一个可能的值都必须至少有一个 case 分支与之对应。在某些不可能涵盖所有值的情况下,你可以使用默认(`default`)分支来涵盖其它所有没有对应的值,这个默认分支必须在`switch`语句的最后面。
|
`switch` 语句必须是完备的。这就是说,每一个可能的值都必须至少有一个 case 分支与之对应。在某些不可能涵盖所有值的情况下,你可以使用默认(`default`)分支来涵盖其它所有没有对应的值,这个默认分支必须在 `switch` 语句的最后面。
|
||||||
|
|
||||||
下面的例子使用`switch`语句来匹配一个名为`someCharacter`的小写字符:
|
下面的例子使用 `switch` 语句来匹配一个名为 `someCharacter` 的小写字符:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let someCharacter: Character = "z"
|
let someCharacter: Character = "z"
|
||||||
@ -369,17 +369,17 @@ default:
|
|||||||
// 输出 "The last letter of the alphabet"
|
// 输出 "The last letter of the alphabet"
|
||||||
```
|
```
|
||||||
|
|
||||||
在这个例子中,第一个 case 分支用于匹配第一个英文字母`a`,第二个 case 分支用于匹配最后一个字母`z`。
|
在这个例子中,第一个 case 分支用于匹配第一个英文字母 `a`,第二个 case 分支用于匹配最后一个字母 `z`。
|
||||||
因为`switch`语句必须有一个case分支用于覆盖所有可能的字符,而不仅仅是所有的英文字母,所以switch语句使用`default`分支来匹配除了`a`和`z`外的所有值,这个分支保证了swith语句的完备性。
|
因为 `switch` 语句必须有一个 case 分支用于覆盖所有可能的字符,而不仅仅是所有的英文字母,所以 switch 语句使用 `default` 分支来匹配除了 `a` 和 `z` 外的所有值,这个分支保证了 swith 语句的完备性。
|
||||||
|
|
||||||
<a name="no_implicit_fallthrough"></a>
|
<a name="no_implicit_fallthrough"></a>
|
||||||
#### 不存在隐式的贯穿
|
#### 不存在隐式的贯穿
|
||||||
|
|
||||||
与 C 和 Objective-C 中的`switch`语句不同,在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止`switch`语句,而不会继续执行下一个 case 分支。这也就是说,不需要在 case 分支中显式地使用`break`语句。这使得`switch`语句更安全、更易用,也避免了因忘记写`break`语句而产生的错误。
|
与 C 和 Objective-C 中的 `switch` 语句不同,在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止 `switch` 语句,而不会继续执行下一个 case 分支。这也就是说,不需要在 case 分支中显式地使用 `break` 语句。这使得 `switch` 语句更安全、更易用,也避免了因忘记写 `break` 语句而产生的错误。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
虽然在Swift中`break`不是必须的,但你依然可以在 case 分支中的代码执行完毕前使用`break`跳出,详情请参见[Switch 语句中的 break](#break_in_a_switch_statement)。
|
虽然在 Swift 中 `break` 不是必须的,但你依然可以在 case 分支中的代码执行完毕前使用 `break` 跳出,详情请参见[Switch 语句中的 break](#break_in_a_switch_statement)。
|
||||||
|
|
||||||
每一个 case 分支都*必须*包含至少一条语句。像下面这样书写代码是无效的,因为第一个 case 分支是空的:
|
每一个 case 分支都*必须*包含至少一条语句。像下面这样书写代码是无效的,因为第一个 case 分支是空的:
|
||||||
|
|
||||||
@ -395,9 +395,9 @@ default:
|
|||||||
// 这段代码会报编译错误
|
// 这段代码会报编译错误
|
||||||
```
|
```
|
||||||
|
|
||||||
不像 C 语言里的`switch`语句,在 Swift 中,`switch`语句不会一起匹配`"a"`和`"A"`。相反的,上面的代码会引起编译期错误:`case "a": 不包含任何可执行语句`——这就避免了意外地从一个 case 分支贯穿到另外一个,使得代码更安全、也更直观。
|
不像 C 语言里的 `switch` 语句,在 Swift 中,`switch` 语句不会一起匹配 `"a"` 和 `"A"`。相反的,上面的代码会引起编译期错误:`case "a": 不包含任何可执行语句 `——这就避免了意外地从一个 case 分支贯穿到另外一个,使得代码更安全、也更直观。
|
||||||
|
|
||||||
为了让单个case同时匹配`a`和`A`,可以将这个两个值组合成一个复合匹配,并且用逗号分开:
|
为了让单个 case 同时匹配 `a` 和 `A`,可以将这个两个值组合成一个复合匹配,并且用逗号分开:
|
||||||
```swift
|
```swift
|
||||||
let anotherCharacter: Character = "a"
|
let anotherCharacter: Character = "a"
|
||||||
switch anotherCharacter {
|
switch anotherCharacter {
|
||||||
@ -412,7 +412,7 @@ default:
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 如果想要显式贯穿case分支,请使用`fallthrough`语句,详情请参考[贯穿](#fallthrough)。
|
> 如果想要显式贯穿 case 分支,请使用 `fallthrough` 语句,详情请参考[贯穿](#fallthrough)。
|
||||||
|
|
||||||
<a name="interval_matching"></a>
|
<a name="interval_matching"></a>
|
||||||
#### 区间匹配
|
#### 区间匹配
|
||||||
@ -441,14 +441,14 @@ print("There are \(naturalCount) \(countedThings).")
|
|||||||
// 输出 "There are dozens of moons orbiting Saturn."
|
// 输出 "There are dozens of moons orbiting Saturn."
|
||||||
```
|
```
|
||||||
|
|
||||||
在上例中,`approximateCount`在一个`switch`声明中被评估。每一个`case`都与之进行比较。因为`approximateCount`落在了 12 到 100 的区间,所以`naturalCount`等于`"dozens of"`值,并且此后的执行跳出了`switch`语句。
|
在上例中,`approximateCount` 在一个 `switch` 声明中被评估。每一个 `case` 都与之进行比较。因为 `approximateCount` 落在了 12 到 100 的区间,所以 `naturalCount` 等于 `"dozens of"` 值,并且此后的执行跳出了 `switch` 语句。
|
||||||
|
|
||||||
<a name="tuples"></a>
|
<a name="tuples"></a>
|
||||||
#### 元组
|
#### 元组
|
||||||
|
|
||||||
我们可以使用元组在同一个`switch`语句中测试多个值。元组中的元素可以是值,也可以是区间。另外,使用下划线(`_`)来匹配所有可能的值。
|
我们可以使用元组在同一个 `switch` 语句中测试多个值。元组中的元素可以是值,也可以是区间。另外,使用下划线(`_`)来匹配所有可能的值。
|
||||||
|
|
||||||
下面的例子展示了如何使用一个`(Int, Int)`类型的元组来分类下图中的点(x, y):
|
下面的例子展示了如何使用一个 `(Int, Int)` 类型的元组来分类下图中的点(x, y):
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let somePoint = (1, 1)
|
let somePoint = (1, 1)
|
||||||
@ -469,16 +469,16 @@ default:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
在上面的例子中,`switch`语句会判断某个点是否是原点(0, 0),是否在红色的x轴上,是否在橘黄色的y轴上,是否在一个以原点为中心的4x4的蓝色矩形里,或者在这个矩形外面。
|
在上面的例子中,`switch` 语句会判断某个点是否是原点(0, 0),是否在红色的 x 轴上,是否在橘黄色的 y 轴上,是否在一个以原点为中心的4x4的蓝色矩形里,或者在这个矩形外面。
|
||||||
|
|
||||||
不像 C 语言,Swift 允许多个 case 匹配同一个值。实际上,在这个例子中,点(0, 0)可以匹配所有_四个 case_。但是,如果存在多个匹配,那么只会执行第一个被匹配到的 case 分支。考虑点(0, 0)会首先匹配`case (0, 0)`,因此剩下的能够匹配的分支都会被忽视掉。
|
不像 C 语言,Swift 允许多个 case 匹配同一个值。实际上,在这个例子中,点(0, 0)可以匹配所有_四个 case_。但是,如果存在多个匹配,那么只会执行第一个被匹配到的 case 分支。考虑点(0, 0)会首先匹配 `case (0, 0)`,因此剩下的能够匹配的分支都会被忽视掉。
|
||||||
|
|
||||||
<a name="value_bindings"></a>
|
<a name="value_bindings"></a>
|
||||||
#### 值绑定(Value Bindings)
|
#### 值绑定(Value Bindings)
|
||||||
|
|
||||||
case 分支允许将匹配的值声明为临时常量或变量,并且在case分支体内使用 —— 这种行为被称为*值绑定*(value binding),因为匹配的值在case分支体内,与临时的常量或变量绑定。
|
case 分支允许将匹配的值声明为临时常量或变量,并且在 case 分支体内使用 —— 这种行为被称为*值绑定*(value binding),因为匹配的值在 case 分支体内,与临时的常量或变量绑定。
|
||||||
|
|
||||||
下面的例子将下图中的点(x, y),使用`(Int, Int)`类型的元组表示,然后分类表示:
|
下面的例子将下图中的点(x, y),使用 `(Int, Int)` 类型的元组表示,然后分类表示:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let anotherPoint = (2, 0)
|
let anotherPoint = (2, 0)
|
||||||
@ -495,18 +495,18 @@ case let (x, y):
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
在上面的例子中,`switch`语句会判断某个点是否在红色的x轴上,是否在橘黄色的y轴上,或者不在坐标轴上。
|
在上面的例子中,`switch` 语句会判断某个点是否在红色的 x 轴上,是否在橘黄色的 y 轴上,或者不在坐标轴上。
|
||||||
|
|
||||||
这三个 case 都声明了常量`x`和`y`的占位符,用于临时获取元组`anotherPoint`的一个或两个值。第一个 case ——`case (let x, 0)`将匹配一个纵坐标为`0`的点,并把这个点的横坐标赋给临时的常量`x`。类似的,第二个 case ——`case (0, let y)`将匹配一个横坐标为`0`的点,并把这个点的纵坐标赋给临时的常量`y`。
|
这三个 case 都声明了常量 `x` 和 `y` 的占位符,用于临时获取元组 `anotherPoint` 的一个或两个值。第一个 case ——`case (let x, 0)` 将匹配一个纵坐标为 `0` 的点,并把这个点的横坐标赋给临时的常量 `x`。类似的,第二个 case ——`case (0, let y)` 将匹配一个横坐标为 `0` 的点,并把这个点的纵坐标赋给临时的常量 `y`。
|
||||||
|
|
||||||
一旦声明了这些临时的常量,它们就可以在其对应的 case 分支里使用。在这个例子中,它们用于打印给定点的类型。
|
一旦声明了这些临时的常量,它们就可以在其对应的 case 分支里使用。在这个例子中,它们用于打印给定点的类型。
|
||||||
|
|
||||||
请注意,这个`switch`语句不包含默认分支。这是因为最后一个 case ——`case let(x, y)`声明了一个可以匹配余下所有值的元组。这使得`switch`语句已经完备了,因此不需要再书写默认分支。
|
请注意,这个 `switch` 语句不包含默认分支。这是因为最后一个 case ——`case let(x, y)` 声明了一个可以匹配余下所有值的元组。这使得 `switch` 语句已经完备了,因此不需要再书写默认分支。
|
||||||
|
|
||||||
<a name="where"></a>
|
<a name="where"></a>
|
||||||
#### Where
|
#### Where
|
||||||
|
|
||||||
case 分支的模式可以使用`where`语句来判断额外的条件。
|
case 分支的模式可以使用 `where` 语句来判断额外的条件。
|
||||||
|
|
||||||
下面的例子把下图中的点(x, y)进行了分类:
|
下面的例子把下图中的点(x, y)进行了分类:
|
||||||
|
|
||||||
@ -525,16 +525,16 @@ case let (x, y):
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
在上面的例子中,`switch`语句会判断某个点是否在绿色的对角线`x == y`上,是否在紫色的对角线`x == -y`上,或者不在对角线上。
|
在上面的例子中,`switch` 语句会判断某个点是否在绿色的对角线 `x == y` 上,是否在紫色的对角线 `x == -y` 上,或者不在对角线上。
|
||||||
|
|
||||||
这三个 case 都声明了常量`x`和`y`的占位符,用于临时获取元组`yetAnotherPoint`的两个值。这两个常量被用作`where`语句的一部分,从而创建一个动态的过滤器(filter)。当且仅当`where`语句的条件为`true`时,匹配到的 case 分支才会被执行。
|
这三个 case 都声明了常量 `x` 和 `y` 的占位符,用于临时获取元组 `yetAnotherPoint` 的两个值。这两个常量被用作 `where` 语句的一部分,从而创建一个动态的过滤器(filter)。当且仅当 `where` 语句的条件为 `true` 时,匹配到的 case 分支才会被执行。
|
||||||
|
|
||||||
就像是值绑定中的例子,由于最后一个 case 分支匹配了余下所有可能的值,`switch`语句就已经完备了,因此不需要再书写默认分支。
|
就像是值绑定中的例子,由于最后一个 case 分支匹配了余下所有可能的值,`switch` 语句就已经完备了,因此不需要再书写默认分支。
|
||||||
|
|
||||||
<a name="compound_cases"></a>
|
<a name="compound_cases"></a>
|
||||||
#### 复合型 Cases
|
#### 复合型 Cases
|
||||||
|
|
||||||
当多个条件可以使用同一种方法来处理时,可以将这几种可能放在同一个`case`后面,并且用逗号隔开。当case后面的任意一种模式匹配的时候,这条分支就会被匹配。并且,如果匹配列表过长,还可以分行书写:
|
当多个条件可以使用同一种方法来处理时,可以将这几种可能放在同一个 `case` 后面,并且用逗号隔开。当 case 后面的任意一种模式匹配的时候,这条分支就会被匹配。并且,如果匹配列表过长,还可以分行书写:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let someCharacter: Character = "e"
|
let someCharacter: Character = "e"
|
||||||
@ -550,7 +550,7 @@ default:
|
|||||||
// 输出 "e is a vowel"
|
// 输出 "e is a vowel"
|
||||||
```
|
```
|
||||||
|
|
||||||
这个`switch`语句中的第一个case,匹配了英语中的五个小写元音字母。相似的,第二个case匹配了英语中所有的小写辅音字母。最终,`default`分支匹配了其它所有字符。
|
这个 `switch` 语句中的第一个 case,匹配了英语中的五个小写元音字母。相似的,第二个 case 匹配了英语中所有的小写辅音字母。最终,`default` 分支匹配了其它所有字符。
|
||||||
复合匹配同样可以包含值绑定。复合匹配里所有的匹配模式,都必须包含相同的值绑定。并且每一个绑定都必须获取到相同类型的值。这保证了,无论复合匹配中的哪个模式发生了匹配,分支体内的代码,都能获取到绑定的值,并且绑定的值都有一样的类型。
|
复合匹配同样可以包含值绑定。复合匹配里所有的匹配模式,都必须包含相同的值绑定。并且每一个绑定都必须获取到相同类型的值。这保证了,无论复合匹配中的哪个模式发生了匹配,分支体内的代码,都能获取到绑定的值,并且绑定的值都有一样的类型。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
@ -566,7 +566,7 @@ default:
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的case有两个模式:`(let distance, 0)`匹配了在x轴上的值,`(0, let distance)`匹配了在y轴上的值。两个模式都绑定了`distance`,并且`distance`在两种模式下,都是整型——这意味着分支体内的代码,只要case匹配,都可以获取到`distance`值
|
上面的 case 有两个模式:`(let distance, 0)` 匹配了在 x 轴上的值,`(0, let distance)` 匹配了在 y 轴上的值。两个模式都绑定了 `distance`,并且 `distance` 在两种模式下,都是整型——这意味着分支体内的代码,只要 case 匹配,都可以获取到 `distance` 值
|
||||||
|
|
||||||
<a name="control_transfer_statements"></a>
|
<a name="control_transfer_statements"></a>
|
||||||
## 控制转移语句
|
## 控制转移语句
|
||||||
@ -579,12 +579,12 @@ default:
|
|||||||
- `return`
|
- `return`
|
||||||
- `throw`
|
- `throw`
|
||||||
|
|
||||||
我们将会在下面讨论`continue`、`break`和`fallthrough`语句。`return`语句将会在[函数](./06_Functions.html)章节讨论,`throw`语句会在[错误抛出](./18_Error_Handling.html#throwing_errors)章节讨论。
|
我们将会在下面讨论 `continue`、`break` 和 `fallthrough` 语句。`return` 语句将会在[函数](./06_Functions.html)章节讨论,`throw` 语句会在[错误抛出](./18_Error_Handling.html#throwing_errors)章节讨论。
|
||||||
|
|
||||||
<a name="continue"></a>
|
<a name="continue"></a>
|
||||||
### Continue
|
### Continue
|
||||||
|
|
||||||
`continue`语句告诉一个循环体立刻停止本次循环,重新开始下次循环。就好像在说“本次循环我已经执行完了”,但是并不会离开整个循环体。
|
`continue` 语句告诉一个循环体立刻停止本次循环,重新开始下次循环。就好像在说“本次循环我已经执行完了”,但是并不会离开整个循环体。
|
||||||
|
|
||||||
下面的例子把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句:
|
下面的例子把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句:
|
||||||
|
|
||||||
@ -603,30 +603,30 @@ print(puzzleOutput)
|
|||||||
// 输出 "grtmndsthnklk"
|
// 输出 "grtmndsthnklk"
|
||||||
```
|
```
|
||||||
|
|
||||||
在上面的代码中,只要匹配到元音字母或者空格字符,就调用`continue`语句,使本次循环结束,重新开始下次循环。这种行为使`switch`匹配到元音字母和空格字符时不做处理,而不是让每一个匹配到的字符都被打印。
|
在上面的代码中,只要匹配到元音字母或者空格字符,就调用 `continue` 语句,使本次循环结束,重新开始下次循环。这种行为使 `switch` 匹配到元音字母和空格字符时不做处理,而不是让每一个匹配到的字符都被打印。
|
||||||
|
|
||||||
<a name="break"></a>
|
<a name="break"></a>
|
||||||
### Break
|
### Break
|
||||||
|
|
||||||
`break`语句会立刻结束整个控制流的执行。`break` 可以在 `switch` 或循环语句中使用,用来提前结束`switch`或循环语句。
|
`break` 语句会立刻结束整个控制流的执行。`break` 可以在 `switch` 或循环语句中使用,用来提前结束 `switch` 或循环语句。
|
||||||
|
|
||||||
<a name="break_in_a_loop_statement"></a>
|
<a name="break_in_a_loop_statement"></a>
|
||||||
#### 循环语句中的 break
|
#### 循环语句中的 break
|
||||||
|
|
||||||
当在一个循环体中使用`break`时,会立刻中断该循环体的执行,然后跳转到表示循环体结束的大括号(`}`)后的第一行代码。不会再有本次循环的代码被执行,也不会再有下次的循环产生。
|
当在一个循环体中使用 `break` 时,会立刻中断该循环体的执行,然后跳转到表示循环体结束的大括号(`}`)后的第一行代码。不会再有本次循环的代码被执行,也不会再有下次的循环产生。
|
||||||
|
|
||||||
<a name="break_in_a_switch_statement"></a>
|
<a name="break_in_a_switch_statement"></a>
|
||||||
#### Switch 语句中的 break
|
#### Switch 语句中的 break
|
||||||
|
|
||||||
当在一个`switch`代码块中使用`break`时,会立即中断该`switch`代码块的执行,并且跳转到表示`switch`代码块结束的大括号(`}`)后的第一行代码。
|
当在一个 `switch` 代码块中使用 `break` 时,会立即中断该 `switch` 代码块的执行,并且跳转到表示 `switch` 代码块结束的大括号(`}`)后的第一行代码。
|
||||||
|
|
||||||
这种特性可以被用来匹配或者忽略一个或多个分支。因为 Swift 的`switch`需要包含所有的分支而且不允许有为空的分支,有时为了使你的意图更明显,需要特意匹配或者忽略某个分支。那么当你想忽略某个分支时,可以在该分支内写上`break`语句。当那个分支被匹配到时,分支内的`break`语句立即结束`switch`代码块。
|
这种特性可以被用来匹配或者忽略一个或多个分支。因为 Swift 的 `switch` 需要包含所有的分支而且不允许有为空的分支,有时为了使你的意图更明显,需要特意匹配或者忽略某个分支。那么当你想忽略某个分支时,可以在该分支内写上 `break` 语句。当那个分支被匹配到时,分支内的 `break` 语句立即结束 `switch` 代码块。
|
||||||
|
|
||||||
>注意
|
> 注意
|
||||||
>
|
>
|
||||||
>当一个`switch`分支仅仅包含注释时,会被报编译时错误。注释不是代码语句而且也不能让`switch`分支达到被忽略的效果。你应该使用`break`来忽略某个分支。
|
> 当一个 `switch` 分支仅仅包含注释时,会被报编译时错误。注释不是代码语句而且也不能让 `switch` 分支达到被忽略的效果。你应该使用 `break` 来忽略某个分支。
|
||||||
|
|
||||||
下面的例子通过`switch`来判断一个`Character`值是否代表下面四种语言之一。为了简洁,多个值被包含在了同一个分支情况中。
|
下面的例子通过 `switch` 来判断一个 `Character` 值是否代表下面四种语言之一。为了简洁,多个值被包含在了同一个分支情况中。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let numberSymbol: Character = "三" // 简体中文里的数字 3
|
let numberSymbol: Character = "三" // 简体中文里的数字 3
|
||||||
@ -651,18 +651,18 @@ if let integerValue = possibleIntegerValue {
|
|||||||
// 输出 "The integer value of 三 is 3."
|
// 输出 "The integer value of 三 is 3."
|
||||||
```
|
```
|
||||||
|
|
||||||
这个例子检查`numberSymbol`是否是拉丁,阿拉伯,中文或者泰语中的`1`到`4`之一。如果被匹配到,该`switch`分支语句给`Int?`类型变量`possibleIntegerValue`设置一个整数值。
|
这个例子检查 `numberSymbol` 是否是拉丁,阿拉伯,中文或者泰语中的 `1` 到 `4` 之一。如果被匹配到,该 `switch` 分支语句给 `Int?` 类型变量 `possibleIntegerValue` 设置一个整数值。
|
||||||
|
|
||||||
当`switch`代码块执行完后,接下来的代码通过使用可选绑定来判断`possibleIntegerValue`是否曾经被设置过值。因为是可选类型的缘故,`possibleIntegerValue`有一个隐式的初始值`nil`,所以仅仅当`possibleIntegerValue`曾被`switch`代码块的前四个分支中的某个设置过一个值时,可选的绑定才会被判定为成功。
|
当 `switch` 代码块执行完后,接下来的代码通过使用可选绑定来判断 `possibleIntegerValue` 是否曾经被设置过值。因为是可选类型的缘故,`possibleIntegerValue` 有一个隐式的初始值 `nil`,所以仅仅当 `possibleIntegerValue` 曾被 `switch` 代码块的前四个分支中的某个设置过一个值时,可选的绑定才会被判定为成功。
|
||||||
|
|
||||||
在上面的例子中,想要把`Character`所有的的可能性都枚举出来是不现实的,所以使用`default`分支来包含所有上面没有匹配到字符的情况。由于这个`default`分支不需要执行任何动作,所以它只写了一条`break`语句。一旦落入到`default`分支中后,`break`语句就完成了该分支的所有代码操作,代码继续向下,开始执行`if let`语句。
|
在上面的例子中,想要把 `Character` 所有的的可能性都枚举出来是不现实的,所以使用 `default` 分支来包含所有上面没有匹配到字符的情况。由于这个 `default` 分支不需要执行任何动作,所以它只写了一条 `break` 语句。一旦落入到 `default` 分支中后,`break` 语句就完成了该分支的所有代码操作,代码继续向下,开始执行 `if let` 语句。
|
||||||
|
|
||||||
<a name="fallthrough"></a>
|
<a name="fallthrough"></a>
|
||||||
### 贯穿 (Fallthrough)
|
### 贯穿 (Fallthrough)
|
||||||
|
|
||||||
在 Swift 里,`switch`语句不会从上一个 case 分支跳转到下一个 case 分支中。相反,只要第一个匹配到的 case 分支完成了它需要执行的语句,整个`switch`代码块完成了它的执行。相比之下,C 语言要求你显式地插入`break`语句到每个 case 分支的末尾来阻止自动落入到下一个 case 分支中。Swift 的这种避免默认落入到下一个分支中的特性意味着它的`switch` 功能要比 C 语言的更加清晰和可预测,可以避免无意识地执行多个 case 分支从而引发的错误。
|
在 Swift 里,`switch` 语句不会从上一个 case 分支跳转到下一个 case 分支中。相反,只要第一个匹配到的 case 分支完成了它需要执行的语句,整个 `switch` 代码块完成了它的执行。相比之下,C 语言要求你显式地插入 `break` 语句到每个 case 分支的末尾来阻止自动落入到下一个 case 分支中。Swift 的这种避免默认落入到下一个分支中的特性意味着它的 `switch` 功能要比 C 语言的更加清晰和可预测,可以避免无意识地执行多个 case 分支从而引发的错误。
|
||||||
|
|
||||||
如果你确实需要 C 风格的贯穿的特性,你可以在每个需要该特性的 case 分支中使用`fallthrough`关键字。下面的例子使用`fallthrough`来创建一个数字的描述语句。
|
如果你确实需要 C 风格的贯穿的特性,你可以在每个需要该特性的 case 分支中使用 `fallthrough` 关键字。下面的例子使用 `fallthrough` 来创建一个数字的描述语句。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let integerToDescribe = 5
|
let integerToDescribe = 5
|
||||||
@ -678,24 +678,24 @@ print(description)
|
|||||||
// 输出 "The number 5 is a prime number, and also an integer."
|
// 输出 "The number 5 is a prime number, and also an integer."
|
||||||
```
|
```
|
||||||
|
|
||||||
这个例子定义了一个`String`类型的变量`description`并且给它设置了一个初始值。函数使用`switch`逻辑来判断`integerToDescribe`变量的值。当`integerToDescribe`的值属于列表中的质数之一时,该函数在`description`后添加一段文字,来表明这个数字是一个质数。然后它使用`fallthrough`关键字来“贯穿”到`default`分支中。`default`分支在`description`的最后添加一段额外的文字,至此`switch`代码块执行完了。
|
这个例子定义了一个 `String` 类型的变量 `description` 并且给它设置了一个初始值。函数使用 `switch` 逻辑来判断 `integerToDescribe` 变量的值。当 `integerToDescribe` 的值属于列表中的质数之一时,该函数在 `description` 后添加一段文字,来表明这个数字是一个质数。然后它使用 `fallthrough` 关键字来“贯穿”到 `default` 分支中。`default` 分支在 `description` 的最后添加一段额外的文字,至此 `switch` 代码块执行完了。
|
||||||
|
|
||||||
如果`integerToDescribe`的值不属于列表中的任何质数,那么它不会匹配到第一个`switch`分支。而这里没有其他特别的分支情况,所以`integerToDescribe`匹配到`default`分支中。
|
如果 `integerToDescribe` 的值不属于列表中的任何质数,那么它不会匹配到第一个 `switch` 分支。而这里没有其他特别的分支情况,所以 `integerToDescribe` 匹配到 `default` 分支中。
|
||||||
|
|
||||||
当`switch`代码块执行完后,使用`print(_:separator:terminator:)`函数打印该数字的描述。在这个例子中,数字`5`被准确的识别为了一个质数。
|
当 `switch` 代码块执行完后,使用 `print(_:separator:terminator:)` 函数打印该数字的描述。在这个例子中,数字 `5` 被准确的识别为了一个质数。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> `fallthrough`关键字不会检查它下一个将会落入执行的 case 中的匹配条件。`fallthrough`简单地使代码继续连接到下一个 case 中的代码,这和 C 语言标准中的`switch`语句特性是一样的。
|
> `fallthrough` 关键字不会检查它下一个将会落入执行的 case 中的匹配条件。`fallthrough` 简单地使代码继续连接到下一个 case 中的代码,这和 C 语言标准中的 `switch` 语句特性是一样的。
|
||||||
|
|
||||||
<a name="labeled_statements"></a>
|
<a name="labeled_statements"></a>
|
||||||
### 带标签的语句
|
### 带标签的语句
|
||||||
|
|
||||||
在 Swift 中,你可以在循环体和条件语句中嵌套循环体和条件语句来创造复杂的控制流结构。并且,循环体和条件语句都可以使用`break`语句来提前结束整个代码块。因此,显式地指明`break`语句想要终止的是哪个循环体或者条件语句,会很有用。类似地,如果你有许多嵌套的循环体,显式指明`continue`语句想要影响哪一个循环体也会非常有用。
|
在 Swift 中,你可以在循环体和条件语句中嵌套循环体和条件语句来创造复杂的控制流结构。并且,循环体和条件语句都可以使用 `break` 语句来提前结束整个代码块。因此,显式地指明 `break` 语句想要终止的是哪个循环体或者条件语句,会很有用。类似地,如果你有许多嵌套的循环体,显式指明 `continue` 语句想要影响哪一个循环体也会非常有用。
|
||||||
|
|
||||||
为了实现这个目的,你可以使用标签(*statement label*)来标记一个循环体或者条件语句,对于一个条件语句,你可以使用`break`加标签的方式,来结束这个被标记的语句。对于一个循环语句,你可以使用`break`或者`continue`加标签,来结束或者继续这条被标记语句的执行。
|
为了实现这个目的,你可以使用标签(*statement label*)来标记一个循环体或者条件语句,对于一个条件语句,你可以使用 `break` 加标签的方式,来结束这个被标记的语句。对于一个循环语句,你可以使用 `break` 或者 `continue` 加标签,来结束或者继续这条被标记语句的执行。
|
||||||
|
|
||||||
声明一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,作为这个语句的前导关键字(introducor keyword),并且该标签后面跟随一个冒号。下面是一个针对`while`循环体的标签语法,同样的规则适用于所有的循环体和条件语句。
|
声明一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,作为这个语句的前导关键字(introducor keyword),并且该标签后面跟随一个冒号。下面是一个针对 `while` 循环体的标签语法,同样的规则适用于所有的循环体和条件语句。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
label name: while condition {
|
label name: while condition {
|
||||||
@ -703,7 +703,7 @@ print(description)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
下面的例子是前面章节中*蛇和梯子*的适配版本,在此版本中,我们将使用一个带有标签的`while`循环体中调用`break`和`continue`语句。这次,游戏增加了一条额外的规则:
|
下面的例子是前面章节中*蛇和梯子*的适配版本,在此版本中,我们将使用一个带有标签的 `while` 循环体中调用 `break` 和 `continue` 语句。这次,游戏增加了一条额外的规则:
|
||||||
|
|
||||||
- 为了获胜,你必须*刚好*落在第 25 个方块中。
|
- 为了获胜,你必须*刚好*落在第 25 个方块中。
|
||||||
|
|
||||||
@ -713,7 +713,7 @@ print(description)
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
`finalSquare`、`board`、`square`和`diceRoll`值被和之前一样的方式初始化:
|
`finalSquare`、`board`、`square` 和 `diceRoll` 值被和之前一样的方式初始化:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let finalSquare = 25
|
let finalSquare = 25
|
||||||
@ -724,9 +724,9 @@ var square = 0
|
|||||||
var diceRoll = 0
|
var diceRoll = 0
|
||||||
```
|
```
|
||||||
|
|
||||||
这个版本的游戏使用`while`循环和`switch`语句来实现游戏的逻辑。`while`循环有一个标签名`gameLoop`,来表明它是游戏的主循环。
|
这个版本的游戏使用 `while` 循环和 `switch` 语句来实现游戏的逻辑。`while` 循环有一个标签名 `gameLoop`,来表明它是游戏的主循环。
|
||||||
|
|
||||||
该`while`循环体的条件判断语句是`while square !=finalSquare`,这表明你必须刚好落在方格25中。
|
该 `while` 循环体的条件判断语句是 `while square !=finalSquare`,这表明你必须刚好落在方格25中。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
gameLoop: while square != finalSquare {
|
gameLoop: while square != finalSquare {
|
||||||
@ -748,22 +748,22 @@ gameLoop: while square != finalSquare {
|
|||||||
print("Game over!")
|
print("Game over!")
|
||||||
```
|
```
|
||||||
|
|
||||||
每次循环迭代开始时掷骰子。与之前玩家掷完骰子就立即移动不同,这里使用了`switch`语句来考虑每次移动可能产生的结果,从而决定玩家本次是否能够移动。
|
每次循环迭代开始时掷骰子。与之前玩家掷完骰子就立即移动不同,这里使用了 `switch` 语句来考虑每次移动可能产生的结果,从而决定玩家本次是否能够移动。
|
||||||
|
|
||||||
- 如果骰子数刚好使玩家移动到最终的方格里,游戏结束。`break gameLoop`语句跳转控制去执行`while`循环体后的第一行代码,意味着游戏结束。
|
- 如果骰子数刚好使玩家移动到最终的方格里,游戏结束。`break gameLoop` 语句跳转控制去执行 `while` 循环体后的第一行代码,意味着游戏结束。
|
||||||
- 如果骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子。`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`,能够使游戏的逻辑更加清晰和易于理解。
|
||||||
|
|
||||||
<a name="early_exit"></a>
|
<a name="early_exit"></a>
|
||||||
## 提前退出
|
## 提前退出
|
||||||
|
|
||||||
像`if`语句一样,`guard`的执行取决于一个表达式的布尔值。我们可以使用`guard`语句来要求条件必须为真时,以执行`guard`语句后的代码。不同于`if`语句,一个`guard`语句总是有一个`else`从句,如果条件不为真则执行`else`从句中的代码。
|
像 `if` 语句一样,`guard` 的执行取决于一个表达式的布尔值。我们可以使用 `guard` 语句来要求条件必须为真时,以执行 `guard` 语句后的代码。不同于 `if` 语句,一个 `guard` 语句总是有一个 `else` 从句,如果条件不为真则执行 `else` 从句中的代码。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func greet(person: [String: String]) {
|
func greet(person: [String: String]) {
|
||||||
@ -785,20 +785,20 @@ greet(["name": "Jane", "location": "Cupertino"])
|
|||||||
// 输出 "I hope the weather is nice in Cupertino."
|
// 输出 "I hope the weather is nice in Cupertino."
|
||||||
```
|
```
|
||||||
|
|
||||||
如果`guard`语句的条件被满足,则继续执行`guard`语句大括号后的代码。将变量或者常量的可选绑定作为`guard`语句的条件,都可以保护`guard`语句后面的代码。
|
如果 `guard` 语句的条件被满足,则继续执行 `guard` 语句大括号后的代码。将变量或者常量的可选绑定作为 `guard` 语句的条件,都可以保护 `guard` 语句后面的代码。
|
||||||
|
|
||||||
如果条件不被满足,在`else`分支上的代码就会被执行。这个分支必须转移控制以退出`guard`语句出现的代码段。它可以用控制转移语句如`return`,`break`,`continue`或者`throw`做这件事,或者调用一个不返回的方法或函数,例如`fatalError()`。
|
如果条件不被满足,在 `else` 分支上的代码就会被执行。这个分支必须转移控制以退出 `guard` 语句出现的代码段。它可以用控制转移语句如 `return`,`break`,`continue` 或者 `throw` 做这件事,或者调用一个不返回的方法或函数,例如 `fatalError()`。
|
||||||
|
|
||||||
相比于可以实现同样功能的`if`语句,按需使用`guard`语句会提升我们代码的可读性。它可以使你的代码连贯的被执行而不需要将它包在`else`块中,它可以使你在紧邻条件判断的地方,处理违规的情况。
|
相比于可以实现同样功能的 `if` 语句,按需使用 `guard` 语句会提升我们代码的可读性。它可以使你的代码连贯的被执行而不需要将它包在 `else` 块中,它可以使你在紧邻条件判断的地方,处理违规的情况。
|
||||||
|
|
||||||
<a name="checking_api_availability"></a>
|
<a name="checking_api_availability"></a>
|
||||||
## 检测 API 可用性
|
## 检测 API 可用性
|
||||||
|
|
||||||
Swift内置支持检查 API 可用性,这可以确保我们不会在当前部署机器上,不小心地使用了不可用的API。
|
Swift 内置支持检查 API 可用性,这可以确保我们不会在当前部署机器上,不小心地使用了不可用的 API。
|
||||||
|
|
||||||
编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 API,Swift 会在编译时报错。
|
编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 API,Swift 会在编译时报错。
|
||||||
|
|
||||||
我们在`if`或`guard`语句中使用`可用性条件(availability condition)`去有条件的执行一段代码,来在运行时判断调用的API是否可用。编译器使用从可用性条件语句中获取的信息去验证,在这个代码块中调用的 API 是否可用。
|
我们在 `if` 或 `guard` 语句中使用 `可用性条件(availability condition)`去有条件的执行一段代码,来在运行时判断调用的 API 是否可用。编译器使用从可用性条件语句中获取的信息去验证,在这个代码块中调用的 API 是否可用。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if #available(iOS 10, macOS 10.12, *) {
|
if #available(iOS 10, macOS 10.12, *) {
|
||||||
@ -808,9 +808,9 @@ if #available(iOS 10, macOS 10.12, *) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
以上可用性条件指定,`if`语句的代码块仅仅在 iOS 10 或 macOS 10.12 及更高版本才运行。最后一个参数,`*`,是必须的,用于指定在所有其它平台中,如果版本号高于你的设备指定的最低版本,if语句的代码块将会运行。
|
以上可用性条件指定,`if` 语句的代码块仅仅在 iOS 10 或 macOS 10.12 及更高版本才运行。最后一个参数,`*`,是必须的,用于指定在所有其它平台中,如果版本号高于你的设备指定的最低版本,if 语句的代码块将会运行。
|
||||||
|
|
||||||
在它一般的形式中,可用性条件使用了一个平台名字和版本的列表。平台名字可以是`iOS`,`macOS`,`watchOS`和`tvOS`——请访问[声明属性](../chapter3/06_Attributes.html)来获取完整列表。除了指定像 iOS 8 或 macOS 10.10 的大版本号,也可以指定像 iOS 11.2.6 以及 macOS 10.13.3 的小版本号。
|
在它一般的形式中,可用性条件使用了一个平台名字和版本的列表。平台名字可以是 `iOS`,`macOS`,`watchOS` 和 `tvOS`——请访问[声明属性](../chapter3/06_Attributes.html)来获取完整列表。除了指定像 iOS 8 或 macOS 10.10 的大版本号,也可以指定像 iOS 11.2.6 以及 macOS 10.13.3 的小版本号。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if #available(platform name version, ..., *) {
|
if #available(platform name version, ..., *) {
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
> 3.0
|
> 3.0
|
||||||
> 翻译: [crayygy](https://github.com/crayygy) 2016-09-12
|
> 翻译: [crayygy](https://github.com/crayygy) 2016-09-12
|
||||||
> 校对: [shanks](http://codebuild.me) 2016-09-27
|
> 校对: [shanks](http://codebuild.me) 2016-09-27
|
||||||
|
|
||||||
> 3.0.1,shanks,2016-11-12
|
> 3.0.1,shanks,2016-11-12
|
||||||
|
|
||||||
> 4.0
|
> 4.0
|
||||||
@ -46,7 +47,7 @@ Swift 统一的函数语法非常的灵活,可以用来表示任何函数,
|
|||||||
|
|
||||||
每个函数有个*函数名*,用来描述函数执行的任务。要使用一个函数时,用函数名来“调用”这个函数,并传给它匹配的输入值(称作 *实参* )。函数的实参必须与函数参数表里参数的顺序一致。
|
每个函数有个*函数名*,用来描述函数执行的任务。要使用一个函数时,用函数名来“调用”这个函数,并传给它匹配的输入值(称作 *实参* )。函数的实参必须与函数参数表里参数的顺序一致。
|
||||||
|
|
||||||
下面例子中的函数的名字是`greet(person:)`,之所以叫这个名字,是因为这个函数用一个人的名字当做输入,并返回向这个人问候的语句。为了完成这个任务,你需要定义一个输入参数——一个叫做 `person` 的 `String` 值,和一个包含给这个人问候语的 `String` 类型的返回值:
|
下面例子中的函数的名字是 `greet(person:)`,之所以叫这个名字,是因为这个函数用一个人的名字当做输入,并返回向这个人问候的语句。为了完成这个任务,你需要定义一个输入参数——一个叫做 `person` 的 `String` 值,和一个包含给这个人问候语的 `String` 类型的返回值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func greet(person: String) -> String {
|
func greet(person: String) -> String {
|
||||||
@ -66,15 +67,15 @@ print(greet(person: "Brian"))
|
|||||||
// 打印 "Hello, Brian!"
|
// 打印 "Hello, 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` 的当前值。
|
||||||
|
|
||||||
你可以用不同的输入值多次调用 `greet(person:)`。上面的例子展示的是用`"Anna"`和`"Brian"`调用的结果,该函数分别返回了不同的结果。
|
你可以用不同的输入值多次调用 `greet(person:)`。上面的例子展示的是用 `"Anna"` 和 `"Brian"` 调用的结果,该函数分别返回了不同的结果。
|
||||||
|
|
||||||
为了简化这个函数的定义,可以将问候消息的创建和返回写成一句:
|
为了简化这个函数的定义,可以将问候消息的创建和返回写成一句:
|
||||||
|
|
||||||
@ -125,12 +126,12 @@ print(greet(person: "Tim", alreadyGreeted: true))
|
|||||||
// 打印 "Hello again, Tim!"
|
// 打印 "Hello again, Tim!"
|
||||||
```
|
```
|
||||||
|
|
||||||
你可以通过在括号内使用逗号分隔来传递一个`String`参数值和一个标识为`alreadyGreeted`的`Bool`值,来调用`greet(person:alreadyGreeted:)`函数。注意这个函数和上面`greet(person:)`是不同的。虽然它们都有着同样的名字`greet`,但是`greet(person:alreadyGreeted:)`函数需要两个参数,而`greet(person:)`只需要一个参数。
|
你可以通过在括号内使用逗号分隔来传递一个 `String` 参数值和一个标识为 `alreadyGreeted` 的 `Bool` 值,来调用 `greet(person:alreadyGreeted:)` 函数。注意这个函数和上面 `greet(person:)` 是不同的。虽然它们都有着同样的名字 `greet`,但是 `greet(person:alreadyGreeted:)` 函数需要两个参数,而 `greet(person:)` 只需要一个参数。
|
||||||
|
|
||||||
<a name="functions_without_return_values"></a>
|
<a name="functions_without_return_values"></a>
|
||||||
### 无返回值函数
|
### 无返回值函数
|
||||||
|
|
||||||
函数可以没有返回值。下面是 `greet(person:)` 函数的另一个版本,这个函数直接打印一个`String`值,而不是返回它:
|
函数可以没有返回值。下面是 `greet(person:)` 函数的另一个版本,这个函数直接打印一个 `String` 值,而不是返回它:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func greet(person: String) {
|
func greet(person: String) {
|
||||||
@ -142,9 +143,9 @@ greet(person: "Dave")
|
|||||||
|
|
||||||
因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。
|
因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。
|
||||||
|
|
||||||
>注意
|
> 注意
|
||||||
>
|
>
|
||||||
>严格上来说,虽然没有返回值被定义,`greet(person:)` 函数依然返回了值。没有定义返回类型的函数会返回一个特殊的`Void`值。它其实是一个空的元组,没有任何元素,可以写成()。
|
> 严格上来说,虽然没有返回值被定义,`greet(person:)` 函数依然返回了值。没有定义返回类型的函数会返回一个特殊的 `Void` 值。它其实是一个空的元组,没有任何元素,可以写成()。
|
||||||
|
|
||||||
被调用时,一个函数的返回值可以被忽略:
|
被调用时,一个函数的返回值可以被忽略:
|
||||||
|
|
||||||
@ -162,10 +163,11 @@ printWithoutCounting(string: "hello, world")
|
|||||||
// 打印 "hello, world" 但是没有返回任何值
|
// 打印 "hello, world" 但是没有返回任何值
|
||||||
```
|
```
|
||||||
|
|
||||||
第一个函数 `printAndCount(string:)`,输出一个字符串并返回 `Int` 类型的字符数。第二个函数 `printWithoutCounting(string:)`调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,消息依然会由第一个函数输出,但是返回值不会被用到。
|
第一个函数 `printAndCount(string:)`,输出一个字符串并返回 `Int` 类型的字符数。第二个函数 `printWithoutCounting(string:)` 调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,消息依然会由第一个函数输出,但是返回值不会被用到。
|
||||||
|
|
||||||
>注意:
|
> 注意
|
||||||
返回值可以被忽略,但定义了有返回值的函数必须返回一个值,如果在函数定义底部没有返回任何值,将导致编译时错误。
|
>
|
||||||
|
> 返回值可以被忽略,但定义了有返回值的函数必须返回一个值,如果在函数定义底部没有返回任何值,将导致编译时错误。
|
||||||
|
|
||||||
<a name="functions_with_multiple_return_values"></a>
|
<a name="functions_with_multiple_return_values"></a>
|
||||||
### 多重返回值函数
|
### 多重返回值函数
|
||||||
@ -206,11 +208,11 @@ print("min is \(bounds.min) and max is \(bounds.max)")
|
|||||||
<a name="optional_tuple_return_types"></a>
|
<a name="optional_tuple_return_types"></a>
|
||||||
### 可选元组返回类型
|
### 可选元组返回类型
|
||||||
|
|
||||||
如果函数返回的元组类型有可能整个元组都“没有值”,你可以使用*可选的* 元组返回类型反映整个元组可以是`nil`的事实。你可以通过在元组类型的右括号后放置一个问号来定义一个可选元组,例如 `(Int, Int)?` 或 `(String, Int, Bool)?`
|
如果函数返回的元组类型有可能整个元组都“没有值”,你可以使用*可选的* 元组返回类型反映整个元组可以是 `nil` 的事实。你可以通过在元组类型的右括号后放置一个问号来定义一个可选元组,例如 `(Int, Int)?` 或 `(String, Int, Bool)?`
|
||||||
|
|
||||||
>注意
|
> 注意
|
||||||
>
|
>
|
||||||
>可选元组类型如 `(Int, Int)?` 与元组包含可选类型如 `(Int?, Int?)` 是不同的。可选的元组类型,整个元组是可选的,而不只是元组中的每个元素值。
|
> 可选元组类型如 `(Int, Int)?` 与元组包含可选类型如 `(Int?, Int?)` 是不同的。可选的元组类型,整个元组是可选的,而不只是元组中的每个元素值。
|
||||||
|
|
||||||
前面的 `minMax(array:)` 函数返回了一个包含两个 `Int` 值的元组。但是函数不会对传入的数组执行任何安全检查,如果 `array` 参数是一个空数组,如上定义的 `minMax(array:)` 在试图访问 `array[0]` 时会触发一个运行时错误。
|
前面的 `minMax(array:)` 函数返回了一个包含两个 `Int` 值的元组。但是函数不会对传入的数组执行任何安全检查,如果 `array` 参数是一个空数组,如上定义的 `minMax(array:)` 在试图访问 `array[0]` 时会触发一个运行时错误。
|
||||||
|
|
||||||
@ -330,22 +332,22 @@ arithmeticMean(3, 8.25, 18.75)
|
|||||||
// 返回 10.0, 是这 3 个数的平均数。
|
// 返回 10.0, 是这 3 个数的平均数。
|
||||||
```
|
```
|
||||||
|
|
||||||
>注意
|
> 注意
|
||||||
>
|
>
|
||||||
>一个函数最多只能拥有一个可变参数。
|
> 一个函数最多只能拥有一个可变参数。
|
||||||
|
|
||||||
<a name="in_out_parameters"></a>
|
<a name="in_out_parameters"></a>
|
||||||
### 输入输出参数
|
### 输入输出参数
|
||||||
|
|
||||||
函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为*输入输出参数(In-Out Parameters)*。
|
函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为*输入输出参数(In-Out Parameters)*。
|
||||||
|
|
||||||
定义一个输入输出参数时,在参数定义前加 `inout` 关键字。一个`输入输出参数`有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。想获取更多的关于输入输出参数的细节和相关的编译器优化,请查看[输入输出参数](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID545)一节。
|
定义一个输入输出参数时,在参数定义前加 `inout` 关键字。一个 `输入输出参数`有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。想获取更多的关于输入输出参数的细节和相关的编译器优化,请查看[输入输出参数](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID545)一节。
|
||||||
|
|
||||||
你只能传递变量给输入输出参数。你不能传入常量或者字面量,因为这些量是不能被修改的。当传入的参数作为输入输出参数时,需要在参数名前加 `&` 符,表示这个值可以被函数修改。
|
你只能传递变量给输入输出参数。你不能传入常量或者字面量,因为这些量是不能被修改的。当传入的参数作为输入输出参数时,需要在参数名前加 `&` 符,表示这个值可以被函数修改。
|
||||||
|
|
||||||
>注意
|
> 注意
|
||||||
>
|
>
|
||||||
>输入输出参数不能有默认值,而且可变参数不能用 `inout` 标记。
|
> 输入输出参数不能有默认值,而且可变参数不能用 `inout` 标记。
|
||||||
|
|
||||||
下例中,`swapTwoInts(_:_:)` 函数有两个分别叫做 `a` 和 `b` 的输入输出参数:
|
下例中,`swapTwoInts(_:_:)` 函数有两个分别叫做 `a` 和 `b` 的输入输出参数:
|
||||||
|
|
||||||
@ -371,9 +373,9 @@ 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>
|
||||||
## 函数类型
|
## 函数类型
|
||||||
@ -470,7 +472,7 @@ printMathResult(addTwoInts, 3, 5)
|
|||||||
|
|
||||||
你可以用函数类型作为另一个函数的返回类型。你需要做的是在返回箭头(->)后写一个完整的函数类型。
|
你可以用函数类型作为另一个函数的返回类型。你需要做的是在返回箭头(->)后写一个完整的函数类型。
|
||||||
|
|
||||||
下面的这个例子中定义了两个简单函数,分别是 `stepForward(_:)` 和 `stepBackward(_:)`。`stepForward(_:)`函数返回一个比输入值大 `1` 的值。`stepBackward(_:)` 函数返回一个比输入值小 `1` 的值。这两个函数的类型都是 `(Int) -> Int`:
|
下面的这个例子中定义了两个简单函数,分别是 `stepForward(_:)` 和 `stepBackward(_:)`。`stepForward(_:)` 函数返回一个比输入值大 `1` 的值。`stepBackward(_:)` 函数返回一个比输入值小 `1` 的值。这两个函数的类型都是 `(Int) -> Int`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func stepForward(_ input: Int) -> Int {
|
func stepForward(_ input: Int) -> Int {
|
||||||
@ -499,7 +501,7 @@ let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
|
|||||||
|
|
||||||
上面这个例子中计算出从 `currentValue` 逐渐接近到0是需要向正数走还是向负数走。`currentValue` 的初始值是 `3`,这意味着 `currentValue > 0` 为真(true),这将使得 `chooseStepFunction(_:)` 返回 `stepBackward(_:)` 函数。一个指向返回的函数的引用保存在了 `moveNearerToZero` 常量中。
|
上面这个例子中计算出从 `currentValue` 逐渐接近到0是需要向正数走还是向负数走。`currentValue` 的初始值是 `3`,这意味着 `currentValue > 0` 为真(true),这将使得 `chooseStepFunction(_:)` 返回 `stepBackward(_:)` 函数。一个指向返回的函数的引用保存在了 `moveNearerToZero` 常量中。
|
||||||
|
|
||||||
现在,`moveNearerToZero`指向了正确的函数,它可以被用来数到零:
|
现在,`moveNearerToZero` 指向了正确的函数,它可以被用来数到零:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
print("Counting to zero:")
|
print("Counting to zero:")
|
||||||
|
|||||||
@ -11,12 +11,13 @@
|
|||||||
> 2.1
|
> 2.1
|
||||||
> 翻译:[100mango](https://github.com/100mango), [magicdict](https://github.com/magicdict)
|
> 翻译:[100mango](https://github.com/100mango), [magicdict](https://github.com/magicdict)
|
||||||
> 校对:[shanks](http://codebuild.me)
|
> 校对:[shanks](http://codebuild.me)
|
||||||
>
|
|
||||||
> 2.2
|
> 2.2
|
||||||
> 翻译+校对:[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.1,shanks,2016-11-12
|
> 3.0.1,shanks,2016-11-12
|
||||||
|
|
||||||
> 4.0
|
> 4.0
|
||||||
@ -39,6 +40,7 @@
|
|||||||
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。被称为*包裹*常量和变量。 Swift 会为你管理在捕获过程中涉及到的所有内存操作。
|
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。被称为*包裹*常量和变量。 Swift 会为你管理在捕获过程中涉及到的所有内存操作。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
|
>
|
||||||
> 如果你不熟悉捕获(capturing)这个概念也不用担心,你可以在[值捕获](#capturing_values)章节对其进行详细了解。
|
> 如果你不熟悉捕获(capturing)这个概念也不用担心,你可以在[值捕获](#capturing_values)章节对其进行详细了解。
|
||||||
|
|
||||||
在[函数](./06_Functions.md)章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:
|
在[函数](./06_Functions.md)章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:
|
||||||
@ -72,7 +74,7 @@ Swift 标准库提供了名为 `sorted(by:)` 的方法,它会根据你所提
|
|||||||
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
|
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
|
||||||
```
|
```
|
||||||
|
|
||||||
`sorted(by:)` 方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值*前面*,排序闭包函数需要返回`true`,反之返回`false`。
|
`sorted(by:)` 方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值*前面*,排序闭包函数需要返回 `true`,反之返回 `false`。
|
||||||
|
|
||||||
该例子对一个 `String` 类型的数组进行排序,因此排序闭包函数类型需为 `(String, String) -> Bool`。
|
该例子对一个 `String` 类型的数组进行排序,因此排序闭包函数类型需为 `(String, String) -> Bool`。
|
||||||
|
|
||||||
@ -113,7 +115,7 @@ reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
|
|||||||
|
|
||||||
需要注意的是内联闭包参数和返回值类型声明与 `backward(_:_:)` 函数类型声明相同。在这两种方式中,都写成了 `(s1: String, s2: String) -> Bool`。然而在内联闭包表达式中,函数和返回值类型都写在*大括号内*,而不是大括号外。
|
需要注意的是内联闭包参数和返回值类型声明与 `backward(_:_:)` 函数类型声明相同。在这两种方式中,都写成了 `(s1: String, s2: String) -> Bool`。然而在内联闭包表达式中,函数和返回值类型都写在*大括号内*,而不是大括号外。
|
||||||
|
|
||||||
闭包的函数体部分由关键字`in`引入。该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
|
闭包的函数体部分由关键字 `in` 引入。该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
|
||||||
|
|
||||||
由于这个闭包的函数体部分如此短,以至于可以将其改写成一行代码:
|
由于这个闭包的函数体部分如此短,以至于可以将其改写成一行代码:
|
||||||
|
|
||||||
@ -151,13 +153,13 @@ reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
|
|||||||
|
|
||||||
Swift 自动为内联闭包提供了参数名称缩写功能,你可以直接通过 `$0`,`$1`,`$2` 来顺序调用闭包的参数,以此类推。
|
Swift 自动为内联闭包提供了参数名称缩写功能,你可以直接通过 `$0`,`$1`,`$2` 来顺序调用闭包的参数,以此类推。
|
||||||
|
|
||||||
如果你在闭包表达式中使用参数名称缩写,你可以在闭包定义中省略参数列表,并且对应参数名称缩写的类型会通过函数类型进行推断。`in`关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
|
如果你在闭包表达式中使用参数名称缩写,你可以在闭包定义中省略参数列表,并且对应参数名称缩写的类型会通过函数类型进行推断。`in` 关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
reversedNames = names.sorted(by: { $0 > $1 } )
|
reversedNames = names.sorted(by: { $0 > $1 } )
|
||||||
```
|
```
|
||||||
|
|
||||||
在这个例子中,`$0`和`$1`表示闭包中第一个和第二个 `String` 类型的参数。
|
在这个例子中,`$0` 和 `$1` 表示闭包中第一个和第二个 `String` 类型的参数。
|
||||||
|
|
||||||
<a name="operator_methods"></a>
|
<a name="operator_methods"></a>
|
||||||
### 运算符方法
|
### 运算符方法
|
||||||
@ -207,7 +209,7 @@ reversedNames = names.sorted { $0 > $1 }
|
|||||||
|
|
||||||
当提供给数组的闭包应用于每个数组元素后,`map(_:)` 方法将返回一个新的数组,数组中包含了与原数组中的元素一一对应的映射后的值。
|
当提供给数组的闭包应用于每个数组元素后,`map(_:)` 方法将返回一个新的数组,数组中包含了与原数组中的元素一一对应的映射后的值。
|
||||||
|
|
||||||
下例介绍了如何在 `map(_:)` 方法中使用尾随闭包将 `Int` 类型数组 `[16, 58, 510]` 转换为包含对应 `String` 类型的值的数组`["OneSix", "FiveEight", "FiveOneZero"]`:
|
下例介绍了如何在 `map(_:)` 方法中使用尾随闭包将 `Int` 类型数组 `[16, 58, 510]` 转换为包含对应 `String` 类型的值的数组 `["OneSix", "FiveEight", "FiveOneZero"]`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let digitNames = [
|
let digitNames = [
|
||||||
@ -244,7 +246,7 @@ let strings = numbers.map {
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 字典 `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`。)
|
||||||
|
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
<a name="enumeration_syntax"></a>
|
<a name="enumeration_syntax"></a>
|
||||||
## 枚举语法
|
## 枚举语法
|
||||||
|
|
||||||
使用`enum`关键词来创建枚举并且把它们的整个定义放在一对大括号内:
|
使用 `enum` 关键词来创建枚举并且把它们的整个定义放在一对大括号内:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
enum SomeEnumeration {
|
enum SomeEnumeration {
|
||||||
@ -65,11 +65,11 @@ 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` 类型。
|
||||||
|
|
||||||
多个成员值可以出现在同一行上,用逗号隔开:
|
多个成员值可以出现在同一行上,用逗号隔开:
|
||||||
|
|
||||||
@ -79,24 +79,24 @@ enum Planet {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
每个枚举定义了一个全新的类型。像 Swift 中其他类型一样,它们的名字(例如`CompassPoint`和`Planet`)应该以一个大写字母开头。给枚举类型起一个单数名字而不是复数名字,以便于:
|
每个枚举定义了一个全新的类型。像 Swift 中其他类型一样,它们的名字(例如 `CompassPoint` 和 `Planet`)应该以一个大写字母开头。给枚举类型起一个单数名字而不是复数名字,以便于:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var directionToHead = CompassPoint.west
|
var directionToHead = CompassPoint.west
|
||||||
```
|
```
|
||||||
|
|
||||||
`directionToHead`的类型可以在它被`CompassPoint`的某个值初始化时推断出来。一旦`directionToHead`被声明为`CompassPoint`类型,你可以使用更简短的点语法将其设置为另一个`CompassPoint`的值:
|
`directionToHead` 的类型可以在它被 `CompassPoint` 的某个值初始化时推断出来。一旦 `directionToHead` 被声明为 `CompassPoint` 类型,你可以使用更简短的点语法将其设置为另一个 `CompassPoint` 的值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
directionToHead = .east
|
directionToHead = .east
|
||||||
```
|
```
|
||||||
|
|
||||||
当`directionToHead`的类型已知时,再次为其赋值可以省略枚举类型名。在使用具有显式类型的枚举值时,这种写法让代码具有更好的可读性。
|
当 `directionToHead` 的类型已知时,再次为其赋值可以省略枚举类型名。在使用具有显式类型的枚举值时,这种写法让代码具有更好的可读性。
|
||||||
|
|
||||||
<a name="matching_enumeration_values_with_a_switch_statement"></a>
|
<a name="matching_enumeration_values_with_a_switch_statement"></a>
|
||||||
## 使用 Switch 语句匹配枚举值
|
## 使用 Switch 语句匹配枚举值
|
||||||
|
|
||||||
你可以使用`switch`语句匹配单个枚举值:
|
你可以使用 `switch` 语句匹配单个枚举值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
directionToHead = .south
|
directionToHead = .south
|
||||||
@ -115,13 +115,13 @@ switch directionToHead {
|
|||||||
|
|
||||||
你可以这样理解这段代码:
|
你可以这样理解这段代码:
|
||||||
|
|
||||||
“判断`directionToHead`的值。当它等于`.north`,打印`“Lots of planets have a north”`。当它等于`.south`,打印`“Watch out for penguins”`。”
|
“判断 `directionToHead` 的值。当它等于 `.north`,打印 `“Lots of planets have a north”`。当它等于 `.south`,打印 `“Watch out for penguins”`。”
|
||||||
|
|
||||||
……以此类推。
|
……以此类推。
|
||||||
|
|
||||||
正如在[控制流](./05_Control_Flow.html)中介绍的那样,在判断一个枚举类型的值时,`switch`语句必须穷举所有情况。如果忽略了`.west`这种情况,上面那段代码将无法通过编译,因为它没有考虑到`CompassPoint`的全部成员。强制穷举确保了枚举成员不会被意外遗漏。
|
正如在[控制流](./05_Control_Flow.html)中介绍的那样,在判断一个枚举类型的值时,`switch` 语句必须穷举所有情况。如果忽略了 `.west` 这种情况,上面那段代码将无法通过编译,因为它没有考虑到 `CompassPoint` 的全部成员。强制穷举确保了枚举成员不会被意外遗漏。
|
||||||
|
|
||||||
当不需要匹配每个枚举成员的时候,你可以提供一个`default`分支来涵盖所有未明确处理的枚举成员:
|
当不需要匹配每个枚举成员的时候,你可以提供一个 `default` 分支来涵盖所有未明确处理的枚举成员:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let somePlanet = Planet.earth
|
let somePlanet = Planet.earth
|
||||||
@ -137,11 +137,11 @@ default:
|
|||||||
<a name="associated_values"></a>
|
<a name="associated_values"></a>
|
||||||
## 关联值
|
## 关联值
|
||||||
|
|
||||||
上一小节的例子演示了如何定义和分类枚举的成员。你可以为`Planet.earth`设置一个常量或者变量,并在赋值之后查看这个值。然而,有时候能够把其他类型的*关联值*和成员值一起存储起来会很有用。这能让你连同成员值一起存储额外的自定义信息,并且你每次在代码中使用该枚举成员时,还可以修改这个关联值。
|
上一小节的例子演示了如何定义和分类枚举的成员。你可以为 `Planet.earth` 设置一个常量或者变量,并在赋值之后查看这个值。然而,有时候能够把其他类型的*关联值*和成员值一起存储起来会很有用。这能让你连同成员值一起存储额外的自定义信息,并且你每次在代码中使用该枚举成员时,还可以修改这个关联值。
|
||||||
|
|
||||||
你可以定义 Swift 枚举来存储任意类型的关联值,如果需要的话,每个枚举成员的关联值类型可以各不相同。枚举的这种特性跟其他语言中的可识别联合(discriminated unions),标签联合(tagged unions),或者变体(variants)相似。
|
你可以定义 Swift 枚举来存储任意类型的关联值,如果需要的话,每个枚举成员的关联值类型可以各不相同。枚举的这种特性跟其他语言中的可识别联合(discriminated unions),标签联合(tagged unions),或者变体(variants)相似。
|
||||||
|
|
||||||
例如,假设一个库存跟踪系统需要利用两种不同类型的条形码来跟踪商品。有些商品上标有使用`0`到`9`的数字的 UPC 格式的一维条形码。每一个条形码都有一个代表“数字系统”的数字,该数字后接五位代表“厂商代码”的数字,接下来是五位代表“产品代码”的数字。最后一个数字是“检查”位,用来验证代码是否被正确扫描:
|
例如,假设一个库存跟踪系统需要利用两种不同类型的条形码来跟踪商品。有些商品上标有使用 `0` 到 `9` 的数字的 UPC 格式的一维条形码。每一个条形码都有一个代表“数字系统”的数字,该数字后接五位代表“厂商代码”的数字,接下来是五位代表“产品代码”的数字。最后一个数字是“检查”位,用来验证代码是否被正确扫描:
|
||||||
|
|
||||||
<img width="252" height="120" alt="" src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/barcode_UPC_2x.png">
|
<img width="252" height="120" alt="" src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/barcode_UPC_2x.png">
|
||||||
|
|
||||||
@ -162,9 +162,9 @@ enum Barcode {
|
|||||||
|
|
||||||
以上代码可以这么理解:
|
以上代码可以这么理解:
|
||||||
|
|
||||||
“定义一个名为`Barcode`的枚举类型,它的一个成员值是具有`(Int,Int,Int,Int)`类型关联值的`upc`,另一个成员值是具有`String`类型关联值的`qrCode`。”
|
“定义一个名为 `Barcode` 的枚举类型,它的一个成员值是具有 `(Int,Int,Int,Int)` 类型关联值的 `upc`,另一个成员值是具有 `String` 类型关联值的 `qrCode`。”
|
||||||
|
|
||||||
这个定义不提供任何`Int`或`String`类型的关联值,它只是定义了,当`Barcode`常量和变量等于`Barcode.upc`或`Barcode.qrCode`时,可以存储的关联值的类型。
|
这个定义不提供任何 `Int` 或 `String` 类型的关联值,它只是定义了,当 `Barcode` 常量和变量等于 `Barcode.upc` 或 `Barcode.qrCode` 时,可以存储的关联值的类型。
|
||||||
|
|
||||||
然后可以使用任意一种条形码类型创建新的条形码,例如:
|
然后可以使用任意一种条形码类型创建新的条形码,例如:
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ enum Barcode {
|
|||||||
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
|
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的例子创建了一个名为`productBarcode`的变量,并将`Barcode.upc`赋值给它,关联的元组值为`(8, 85909, 51226, 3)`。
|
上面的例子创建了一个名为 `productBarcode` 的变量,并将 `Barcode.upc` 赋值给它,关联的元组值为 `(8, 85909, 51226, 3)`。
|
||||||
|
|
||||||
同一个商品可以被分配一个不同类型的条形码,例如:
|
同一个商品可以被分配一个不同类型的条形码,例如:
|
||||||
|
|
||||||
@ -180,9 +180,9 @@ var productBarcode = Barcode.upc(8, 85909, 51226, 3)
|
|||||||
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
|
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
|
||||||
```
|
```
|
||||||
|
|
||||||
这时,原始的`Barcode.upc`和其整数关联值被新的`Barcode.qrCode`和其字符串关联值所替代。`Barcode`类型的常量和变量可以存储一个`.upc`或者一个`.qrCode`(连同它们的关联值),但是在同一时间只能存储这两个值中的一个。
|
这时,原始的 `Barcode.upc` 和其整数关联值被新的 `Barcode.qrCode` 和其字符串关联值所替代。`Barcode` 类型的常量和变量可以存储一个 `.upc` 或者一个 `.qrCode`(连同它们的关联值),但是在同一时间只能存储这两个值中的一个。
|
||||||
|
|
||||||
像先前那样,可以使用一个 switch 语句来检查不同的条形码类型。然而,这一次,关联值可以被提取出来作为 switch 语句的一部分。你可以在`switch`的 case 分支代码中提取每个关联值作为一个常量(用`let`前缀)或者作为一个变量(用`var`前缀)来使用:
|
像先前那样,可以使用一个 switch 语句来检查不同的条形码类型。然而,这一次,关联值可以被提取出来作为 switch 语句的一部分。你可以在 `switch` 的 case 分支代码中提取每个关联值作为一个常量(用 `let` 前缀)或者作为一个变量(用 `var` 前缀)来使用:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
switch productBarcode {
|
switch productBarcode {
|
||||||
@ -194,7 +194,7 @@ case .qrCode(let productCode):
|
|||||||
// 打印 "QR code: ABCDEFGHIJKLMNOP."
|
// 打印 "QR code: ABCDEFGHIJKLMNOP."
|
||||||
```
|
```
|
||||||
|
|
||||||
如果一个枚举成员的所有关联值都被提取为常量,或者都被提取为变量,为了简洁,你可以只在成员名称前标注一个`let`或者`var`:
|
如果一个枚举成员的所有关联值都被提取为常量,或者都被提取为变量,为了简洁,你可以只在成员名称前标注一个 `let` 或者 `var`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
switch productBarcode {
|
switch productBarcode {
|
||||||
@ -221,7 +221,7 @@ enum ASCIIControlCharacter: Character {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
枚举类型`ASCIIControlCharacter`的原始值类型被定义为`Character`,并设置了一些比较常见的 ASCII 控制字符。`Character`的描述详见[字符串和字符](./03_Strings_and_Characters.html)部分。
|
枚举类型 `ASCIIControlCharacter` 的原始值类型被定义为 `Character`,并设置了一些比较常见的 ASCII 控制字符。`Character` 的描述详见[字符串和字符](./03_Strings_and_Characters.html)部分。
|
||||||
|
|
||||||
原始值可以是字符串,字符,或者任意整型值或浮点型值。每个原始值在枚举声明中必须是唯一的。
|
原始值可以是字符串,字符,或者任意整型值或浮点型值。每个原始值在枚举声明中必须是唯一的。
|
||||||
|
|
||||||
@ -234,9 +234,9 @@ enum ASCIIControlCharacter: Character {
|
|||||||
|
|
||||||
在使用原始值为整数或者字符串类型的枚举时,不需要显式地为每一个枚举成员设置原始值,Swift 将会自动为你赋值。
|
在使用原始值为整数或者字符串类型的枚举时,不需要显式地为每一个枚举成员设置原始值,Swift 将会自动为你赋值。
|
||||||
|
|
||||||
例如,当使用整数作为原始值时,隐式赋值的值依次递增`1`。如果第一个枚举成员没有设置原始值,其原始值将为`0`。
|
例如,当使用整数作为原始值时,隐式赋值的值依次递增 `1`。如果第一个枚举成员没有设置原始值,其原始值将为 `0`。
|
||||||
|
|
||||||
下面的枚举是对之前`Planet`这个枚举的一个细化,利用整型的原始值来表示每个行星在太阳系中的顺序:
|
下面的枚举是对之前 `Planet` 这个枚举的一个细化,利用整型的原始值来表示每个行星在太阳系中的顺序:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
enum Planet: Int {
|
enum Planet: Int {
|
||||||
@ -244,11 +244,11 @@ enum Planet: Int {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
在上面的例子中,`Plant.mercury`的显式原始值为`1`,`Planet.venus`的隐式原始值为`2`,依次类推。
|
在上面的例子中,`Plant.mercury` 的显式原始值为 `1`,`Planet.venus` 的隐式原始值为 `2`,依次类推。
|
||||||
|
|
||||||
当使用字符串作为枚举类型的原始值时,每个枚举成员的隐式原始值为该枚举成员的名称。
|
当使用字符串作为枚举类型的原始值时,每个枚举成员的隐式原始值为该枚举成员的名称。
|
||||||
|
|
||||||
下面的例子是`CompassPoint`枚举的细化,使用字符串类型的原始值来表示各个方向的名称:
|
下面的例子是 `CompassPoint` 枚举的细化,使用字符串类型的原始值来表示各个方向的名称:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
enum CompassPoint: String {
|
enum CompassPoint: String {
|
||||||
@ -256,9 +256,9 @@ enum CompassPoint: String {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
上面例子中,`CompassPoint.south`拥有隐式原始值`south`,依次类推。
|
上面例子中,`CompassPoint.south` 拥有隐式原始值 `south`,依次类推。
|
||||||
|
|
||||||
使用枚举成员的`rawValue`属性可以访问该枚举成员的原始值:
|
使用枚举成员的 `rawValue` 属性可以访问该枚举成员的原始值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let earthsOrder = Planet.earth.rawValue
|
let earthsOrder = Planet.earth.rawValue
|
||||||
@ -271,22 +271,22 @@ let sunsetDirection = CompassPoint.west.rawValue
|
|||||||
<a name="initializing_from_a_raw_value"></a>
|
<a name="initializing_from_a_raw_value"></a>
|
||||||
### 使用原始值初始化枚举实例
|
### 使用原始值初始化枚举实例
|
||||||
|
|
||||||
如果在定义枚举类型的时候使用了原始值,那么将会自动获得一个初始化方法,这个方法接收一个叫做`rawValue`的参数,参数类型即为原始值类型,返回值则是枚举成员或`nil`。你可以使用这个初始化方法来创建一个新的枚举实例。
|
如果在定义枚举类型的时候使用了原始值,那么将会自动获得一个初始化方法,这个方法接收一个叫做 `rawValue` 的参数,参数类型即为原始值类型,返回值则是枚举成员或 `nil`。你可以使用这个初始化方法来创建一个新的枚举实例。
|
||||||
|
|
||||||
这个例子利用原始值`7`创建了枚举成员`uranus`:
|
这个例子利用原始值 `7` 创建了枚举成员 `uranus`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let possiblePlanet = Planet(rawValue: 7)
|
let possiblePlanet = Planet(rawValue: 7)
|
||||||
// possiblePlanet 类型为 Planet? 值为 Planet.uranus
|
// possiblePlanet 类型为 Planet? 值为 Planet.uranus
|
||||||
```
|
```
|
||||||
|
|
||||||
然而,并非所有`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`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let positionToFind = 11
|
let positionToFind = 11
|
||||||
@ -303,12 +303,12 @@ if let somePlanet = Planet(rawValue: positionToFind) {
|
|||||||
// 输出 "There isn't a planet at position 11
|
// 输出 "There isn't a planet at position 11
|
||||||
```
|
```
|
||||||
|
|
||||||
这个例子使用了可选绑定(optional binding),试图通过原始值`11`来访问一个行星。`if let somePlanet = Planet(rawValue: 11)`语句创建了一个可选`Planet`,如果可选`Planet`的值存在,就会赋值给`somePlanet`。在这个例子中,无法检索到位置为`11`的行星,所以`else`分支被执行。
|
这个例子使用了可选绑定(optional binding),试图通过原始值 `11` 来访问一个行星。`if let somePlanet = Planet(rawValue: 11)` 语句创建了一个可选 `Planet`,如果可选 `Planet` 的值存在,就会赋值给 `somePlanet`。在这个例子中,无法检索到位置为 `11` 的行星,所以 `else` 分支被执行。
|
||||||
|
|
||||||
<a name="recursive_enumerations"></a>
|
<a name="recursive_enumerations"></a>
|
||||||
## 递归枚举
|
## 递归枚举
|
||||||
|
|
||||||
*递归枚举*是一种枚举类型,它有一个或多个枚举成员使用该枚举类型的实例作为关联值。使用递归枚举时,编译器会插入一个间接层。你可以在枚举成员前加上`indirect`来表示该成员可递归。
|
*递归枚举*是一种枚举类型,它有一个或多个枚举成员使用该枚举类型的实例作为关联值。使用递归枚举时,编译器会插入一个间接层。你可以在枚举成员前加上 `indirect` 来表示该成员可递归。
|
||||||
|
|
||||||
例如,下面的例子中,枚举类型存储了简单的算术表达式:
|
例如,下面的例子中,枚举类型存储了简单的算术表达式:
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ enum ArithmeticExpression {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
你也可以在枚举类型开头加上`indirect`关键字来表明它的所有成员都是可递归的:
|
你也可以在枚举类型开头加上 `indirect` 关键字来表明它的所有成员都是可递归的:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
indirect enum ArithmeticExpression {
|
indirect enum ArithmeticExpression {
|
||||||
@ -330,7 +330,7 @@ indirect enum ArithmeticExpression {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
上面定义的枚举类型可以存储三种算术表达式:纯数字、两个表达式相加、两个表达式相乘。枚举成员`addition`和`multiplication`的关联值也是算术表达式——这些关联值使得嵌套表达式成为可能。例如,表达式`(5 + 4) * 2`,乘号右边是一个数字,左边则是另一个表达式。因为数据是嵌套的,因而用来存储数据的枚举类型也需要支持这种嵌套——这意味着枚举类型需要支持递归。下面的代码展示了使用`ArithmeticExpression `这个递归枚举创建表达式`(5 + 4) * 2`
|
上面定义的枚举类型可以存储三种算术表达式:纯数字、两个表达式相加、两个表达式相乘。枚举成员 `addition` 和 `multiplication` 的关联值也是算术表达式——这些关联值使得嵌套表达式成为可能。例如,表达式 `(5 + 4) * 2`,乘号右边是一个数字,左边则是另一个表达式。因为数据是嵌套的,因而用来存储数据的枚举类型也需要支持这种嵌套——这意味着枚举类型需要支持递归。下面的代码展示了使用 `ArithmeticExpression` 这个递归枚举创建表达式 `(5 + 4) * 2`
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let five = ArithmeticExpression.number(5)
|
let five = ArithmeticExpression.number(5)
|
||||||
|
|||||||
@ -67,7 +67,7 @@ Swift 中类和结构体有很多共同点。共同处在于:
|
|||||||
<a name="definition_syntax"></a>
|
<a name="definition_syntax"></a>
|
||||||
### 定义语法
|
### 定义语法
|
||||||
|
|
||||||
类和结构体有着类似的定义方式。我们通过关键字`class`和`struct`来分别表示类和结构体,并在一对大括号中定义它们的具体内容:
|
类和结构体有着类似的定义方式。我们通过关键字 `class` 和 `struct` 来分别表示类和结构体,并在一对大括号中定义它们的具体内容:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class SomeClass {
|
class SomeClass {
|
||||||
@ -80,7 +80,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`),以便和类型名区分。
|
||||||
|
|
||||||
以下是定义结构体和定义类的示例:
|
以下是定义结构体和定义类的示例:
|
||||||
|
|
||||||
@ -97,14 +97,14 @@ class VideoMode {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
在上面的示例中我们定义了一个名为`Resolution`的结构体,用来描述一个显示器的像素分辨率。这个结构体包含了两个名为`width`和`height`的存储属性。存储属性是被捆绑和存储在类或结构体中的常量或变量。当这两个属性被初始化为整数`0`的时候,它们会被推断为`Int`类型。
|
在上面的示例中我们定义了一个名为 `Resolution` 的结构体,用来描述一个显示器的像素分辨率。这个结构体包含了两个名为 `width` 和 `height` 的存储属性。存储属性是被捆绑和存储在类或结构体中的常量或变量。当这两个属性被初始化为整数 `0` 的时候,它们会被推断为 `Int` 类型。
|
||||||
|
|
||||||
在上面的示例中我们还定义了一个名为`VideoMode`的类,用来描述一个视频显示器的特定模式。这个类包含了四个变量存储属性。第一个是`分辨率`,它被初始化为一个新的`Resolution`结构体的实例,属性类型被推断为`Resolution`。新`VideoMode`实例同时还会初始化其它三个属性,它们分别是,初始值为`false`的`interlaced`,初始值为`0.0`的`frameRate`,以及值为可选`String`的`name`。`name`属性会被自动赋予一个默认值`nil`,意为“没有`name`值”,因为它是一个可选类型。
|
在上面的示例中我们还定义了一个名为 `VideoMode` 的类,用来描述一个视频显示器的特定模式。这个类包含了四个变量存储属性。第一个是 `分辨率`,它被初始化为一个新的 `Resolution` 结构体的实例,属性类型被推断为 `Resolution`。新 `VideoMode` 实例同时还会初始化其它三个属性,它们分别是,初始值为 `false` 的 `interlaced`,初始值为 `0.0` 的 `frameRate`,以及值为可选 `String` 的 `name`。`name` 属性会被自动赋予一个默认值 `nil`,意为“没有 `name` 值”,因为它是一个可选类型。
|
||||||
|
|
||||||
<a name="class_and_structure_instances"></a>
|
<a name="class_and_structure_instances"></a>
|
||||||
### 类和结构体实例
|
### 类和结构体实例
|
||||||
|
|
||||||
`Resolution`结构体和`VideoMode`类的定义仅描述了什么是`Resolution`和`VideoMode`。它们并没有描述一个特定的分辨率(resolution)或者视频模式(video mode)。为了描述一个特定的分辨率或者视频模式,我们需要生成一个它们的实例。
|
`Resolution` 结构体和 `VideoMode` 类的定义仅描述了什么是 `Resolution` 和 `VideoMode`。它们并没有描述一个特定的分辨率(resolution)或者视频模式(video mode)。为了描述一个特定的分辨率或者视频模式,我们需要生成一个它们的实例。
|
||||||
|
|
||||||
生成结构体和类实例的语法非常相似:
|
生成结构体和类实例的语法非常相似:
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ let someResolution = Resolution()
|
|||||||
let someVideoMode = VideoMode()
|
let someVideoMode = VideoMode()
|
||||||
```
|
```
|
||||||
|
|
||||||
结构体和类都使用构造器语法来生成新的实例。构造器语法的最简单形式是在结构体或者类的类型名称后跟随一对空括号,如`Resolution()`或`VideoMode()`。通过这种方式所创建的类或者结构体实例,其属性均会被初始化为默认值。[构造过程](./14_Initialization.html)章节会对类和结构体的初始化进行更详细的讨论。
|
结构体和类都使用构造器语法来生成新的实例。构造器语法的最简单形式是在结构体或者类的类型名称后跟随一对空括号,如 `Resolution()` 或 `VideoMode()`。通过这种方式所创建的类或者结构体实例,其属性均会被初始化为默认值。[构造过程](./14_Initialization.html)章节会对类和结构体的初始化进行更详细的讨论。
|
||||||
|
|
||||||
<a name="accessing_properties"></a>
|
<a name="accessing_properties"></a>
|
||||||
### 属性访问
|
### 属性访问
|
||||||
@ -125,9 +125,9 @@ print("The width of someResolution is \(someResolution.width)")
|
|||||||
// 打印 "The width of someResolution is 0"
|
// 打印 "The width of someResolution is 0"
|
||||||
```
|
```
|
||||||
|
|
||||||
在上面的例子中,`someResolution.width`引用`someResolution`的`width`属性,返回`width`的初始值`0`。
|
在上面的例子中,`someResolution.width` 引用 `someResolution` 的 `width` 属性,返回 `width` 的初始值 `0`。
|
||||||
|
|
||||||
你也可以访问子属性,如`VideoMode`中`Resolution`属性的`width`属性:
|
你也可以访问子属性,如 `VideoMode` 中 `Resolution` 属性的 `width` 属性:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
print("The width of someVideoMode is \(someVideoMode.resolution.width)")
|
print("The width of someVideoMode is \(someVideoMode.resolution.width)")
|
||||||
@ -144,7 +144,7 @@ print("The width of someVideoMode is now \(someVideoMode.resolution.width)")
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 与 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>
|
||||||
### 结构体类型的成员逐一构造器
|
### 结构体类型的成员逐一构造器
|
||||||
@ -166,38 +166,38 @@ let vga = Resolution(width: 640, height: 480)
|
|||||||
|
|
||||||
在 Swift 中,所有的结构体和枚举类型都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。
|
在 Swift 中,所有的结构体和枚举类型都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。
|
||||||
|
|
||||||
请看下面这个示例,其使用了前一个示例中的`Resolution`结构体:
|
请看下面这个示例,其使用了前一个示例中的 `Resolution` 结构体:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let hd = Resolution(width: 1920, height: 1080)
|
let hd = Resolution(width: 1920, height: 1080)
|
||||||
var cinema = hd
|
var cinema = hd
|
||||||
```
|
```
|
||||||
|
|
||||||
在以上示例中,声明了一个名为`hd`的常量,其值为一个初始化为全高清视频分辨率(`1920` 像素宽,`1080` 像素高)的`Resolution`实例。
|
在以上示例中,声明了一个名为 `hd` 的常量,其值为一个初始化为全高清视频分辨率(`1920` 像素宽,`1080` 像素高)的 `Resolution` 实例。
|
||||||
|
|
||||||
然后示例中又声明了一个名为`cinema`的变量,并将`hd`赋值给它。因为`Resolution`是一个结构体,所以`cinema`的值其实是`hd`的一个拷贝副本,而不是`hd`本身。尽管`hd`和`cinema`有着相同的宽(width)和高(height),但是在幕后它们是两个完全不同的实例。
|
然后示例中又声明了一个名为 `cinema` 的变量,并将 `hd` 赋值给它。因为 `Resolution` 是一个结构体,所以 `cinema` 的值其实是 `hd` 的一个拷贝副本,而不是 `hd` 本身。尽管 `hd` 和 `cinema` 有着相同的宽(width)和高(height),但是在幕后它们是两个完全不同的实例。
|
||||||
|
|
||||||
下面,为了符合数码影院放映的需求(`2048` 像素宽,`1080` 像素高),`cinema`的`width`属性需要作如下修改:
|
下面,为了符合数码影院放映的需求(`2048` 像素宽,`1080` 像素高),`cinema` 的 `width` 属性需要作如下修改:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
cinema.width = 2048
|
cinema.width = 2048
|
||||||
```
|
```
|
||||||
|
|
||||||
这里,将会显示`cinema`的`width`属性确已改为了`2048`:
|
这里,将会显示 `cinema` 的 `width` 属性确已改为了 `2048`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
print("cinema is now \(cinema.width) pixels wide")
|
print("cinema is now \(cinema.width) pixels wide")
|
||||||
// 打印 "cinema is now 2048 pixels wide"
|
// 打印 "cinema is now 2048 pixels wide"
|
||||||
```
|
```
|
||||||
|
|
||||||
然而,初始的`hd`实例中`width`属性还是`1920`:
|
然而,初始的 `hd` 实例中 `width` 属性还是 `1920`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
print("hd is still \(hd.width) pixels wide")
|
print("hd is still \(hd.width) pixels wide")
|
||||||
// 打印 "hd is still 1920 pixels wide"
|
// 打印 "hd is still 1920 pixels wide"
|
||||||
```
|
```
|
||||||
|
|
||||||
在将`hd`赋予给`cinema`的时候,实际上是将`hd`中所存储的值进行拷贝,然后将拷贝的数据存储到新的`cinema`实例中。结果就是两个完全独立的实例碰巧包含有相同的数值。由于两者相互独立,因此将`cinema`的`width`修改为`2048`并不会影响`hd`中的`width`的值。
|
在将 `hd` 赋予给 `cinema` 的时候,实际上是将 `hd` 中所存储的值进行拷贝,然后将拷贝的数据存储到新的 `cinema` 实例中。结果就是两个完全独立的实例碰巧包含有相同的数值。由于两者相互独立,因此将 `cinema` 的 `width` 修改为 `2048` 并不会影响 `hd` 中的 `width` 的值。
|
||||||
|
|
||||||
枚举也遵循相同的行为准则:
|
枚举也遵循相同的行为准则:
|
||||||
|
|
||||||
@ -214,14 +214,14 @@ if rememberedDirection == .West {
|
|||||||
// 打印 "The remembered direction is still .West"
|
// 打印 "The remembered direction is still .West"
|
||||||
```
|
```
|
||||||
|
|
||||||
上例中`rememberedDirection`被赋予了`currentDirection`的值,实际上它被赋予的是值的一个拷贝。赋值过程结束后再修改`currentDirection`的值并不影响`rememberedDirection`所储存的原始值的拷贝。
|
上例中 `rememberedDirection` 被赋予了 `currentDirection` 的值,实际上它被赋予的是值的一个拷贝。赋值过程结束后再修改 `currentDirection` 的值并不影响 `rememberedDirection` 所储存的原始值的拷贝。
|
||||||
|
|
||||||
<a name="classes_are_reference_types"></a>
|
<a name="classes_are_reference_types"></a>
|
||||||
## 类是引用类型
|
## 类是引用类型
|
||||||
|
|
||||||
与值类型不同,*引用类型*在被赋予到一个变量、常量或者被传递到一个函数时,其值不会被拷贝。因此,引用的是已存在的实例本身而不是其拷贝。
|
与值类型不同,*引用类型*在被赋予到一个变量、常量或者被传递到一个函数时,其值不会被拷贝。因此,引用的是已存在的实例本身而不是其拷贝。
|
||||||
|
|
||||||
请看下面这个示例,其使用了之前定义的`VideoMode`类:
|
请看下面这个示例,其使用了之前定义的 `VideoMode` 类:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let tenEighty = VideoMode()
|
let tenEighty = VideoMode()
|
||||||
@ -231,25 +231,25 @@ tenEighty.name = "1080i"
|
|||||||
tenEighty.frameRate = 25.0
|
tenEighty.frameRate = 25.0
|
||||||
```
|
```
|
||||||
|
|
||||||
以上示例中,声明了一个名为`tenEighty`的常量,其引用了一个`VideoMode`类的新实例。在之前的示例中,这个视频模式(video mode)被赋予了HD分辨率(`1920`*`1080`)的一个拷贝(即`hd`实例)。同时设置为`interlaced`,命名为`“1080i”`。最后,其帧率是`25.0`帧每秒。
|
以上示例中,声明了一个名为 `tenEighty` 的常量,其引用了一个 `VideoMode` 类的新实例。在之前的示例中,这个视频模式(video mode)被赋予了 HD 分辨率(`1920`*`1080`)的一个拷贝(即 `hd` 实例)。同时设置为 `interlaced`,命名为 `“1080i”`。最后,其帧率是 `25.0` 帧每秒。
|
||||||
|
|
||||||
然后,`tenEighty`被赋予名为`alsoTenEighty`的新常量,同时对`alsoTenEighty`的帧率进行修改:
|
然后,`tenEighty` 被赋予名为 `alsoTenEighty` 的新常量,同时对 `alsoTenEighty` 的帧率进行修改:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let alsoTenEighty = tenEighty
|
let alsoTenEighty = tenEighty
|
||||||
alsoTenEighty.frameRate = 30.0
|
alsoTenEighty.frameRate = 30.0
|
||||||
```
|
```
|
||||||
|
|
||||||
因为类是引用类型,所以`tenEight`和`alsoTenEight`实际上引用的是相同的`VideoMode`实例。换句话说,它们是同一个实例的两种叫法。
|
因为类是引用类型,所以 `tenEight` 和 `alsoTenEight` 实际上引用的是相同的 `VideoMode` 实例。换句话说,它们是同一个实例的两种叫法。
|
||||||
|
|
||||||
下面,通过查看`tenEighty`的`frameRate`属性,我们会发现它正确的显示了所引用的`VideoMode`实例的新帧率,其值为`30.0`:
|
下面,通过查看 `tenEighty` 的 `frameRate` 属性,我们会发现它正确的显示了所引用的 `VideoMode` 实例的新帧率,其值为 `30.0`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
|
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
|
||||||
// 打印 "The frameRate property of theEighty is now 30.0"
|
// 打印 "The frameRate property of theEighty is now 30.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
需要注意的是`tenEighty`和`alsoTenEighty`被声明为常量而不是变量。然而你依然可以改变`tenEighty.frameRate`和`alsoTenEighty.frameRate`,因为`tenEighty`和`alsoTenEighty`这两个常量的值并未改变。它们并不“存储”这个`VideoMode`实例,而仅仅是对`VideoMode`实例的引用。所以,改变的是被引用的`VideoMode`的`frameRate`属性,而不是引用`VideoMode`的常量的值。
|
需要注意的是 `tenEighty` 和 `alsoTenEighty` 被声明为常量而不是变量。然而你依然可以改变 `tenEighty.frameRate` 和 `alsoTenEighty.frameRate`,因为 `tenEighty` 和 `alsoTenEighty` 这两个常量的值并未改变。它们并不“存储”这个 `VideoMode` 实例,而仅仅是对 `VideoMode` 实例的引用。所以,改变的是被引用的 `VideoMode` 的 `frameRate` 属性,而不是引用 `VideoMode` 的常量的值。
|
||||||
|
|
||||||
<a name="identity_operators"></a>
|
<a name="identity_operators"></a>
|
||||||
### 恒等运算符
|
### 恒等运算符
|
||||||
@ -298,18 +298,18 @@ if tenEighty === alsoTenEighty {
|
|||||||
|
|
||||||
举例来说,以下情境中适合使用结构体:
|
举例来说,以下情境中适合使用结构体:
|
||||||
|
|
||||||
* 几何形状的大小,封装一个`width`属性和`height`属性,两者均为`Double`类型。
|
* 几何形状的大小,封装一个 `width` 属性和 `height` 属性,两者均为 `Double` 类型。
|
||||||
* 一定范围内的路径,封装一个`start`属性和`length`属性,两者均为`Int`类型。
|
* 一定范围内的路径,封装一个 `start` 属性和 `length` 属性,两者均为 `Int` 类型。
|
||||||
* 三维坐标系内一点,封装`x`,`y`和`z`属性,三者均为`Double`类型。
|
* 三维坐标系内一点,封装 `x`,`y` 和 `z` 属性,三者均为 `Double` 类型。
|
||||||
|
|
||||||
在所有其它案例中,定义一个类,生成一个它的实例,并通过引用来管理和传递。实际中,这意味着绝大部分的自定义数据构造都应该是类,而非结构体。
|
在所有其它案例中,定义一个类,生成一个它的实例,并通过引用来管理和传递。实际中,这意味着绝大部分的自定义数据构造都应该是类,而非结构体。
|
||||||
|
|
||||||
<a name="assignment_and_copy_behavior_for_strings_arrays_and_dictionaries"></a>
|
<a name="assignment_and_copy_behavior_for_strings_arrays_and_dictionaries"></a>
|
||||||
## 字符串、数组、和字典类型的赋值与复制行为
|
## 字符串、数组、和字典类型的赋值与复制行为
|
||||||
|
|
||||||
Swift 中,许多基本类型,诸如`String`,`Array`和`Dictionary`类型均以结构体的形式实现。这意味着被赋值给新的常量或变量,或者被传入函数或方法中时,它们的值会被拷贝。
|
Swift 中,许多基本类型,诸如 `String`,`Array` 和 `Dictionary` 类型均以结构体的形式实现。这意味着被赋值给新的常量或变量,或者被传入函数或方法中时,它们的值会被拷贝。
|
||||||
|
|
||||||
Objective-C 中`NSString`,`NSArray`和`NSDictionary`类型均以类的形式实现,而并非结构体。它们在被赋值或者被传入函数或方法时,不会发生值拷贝,而是传递现有实例的引用。
|
Objective-C 中 `NSString`,`NSArray` 和 `NSDictionary` 类型均以类的形式实现,而并非结构体。它们在被赋值或者被传入函数或方法时,不会发生值拷贝,而是传递现有实例的引用。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
|
|||||||
@ -118,7 +118,7 @@ manager.data.append("Some more data")
|
|||||||
|
|
||||||
`DataManager` 管理数据时也可能不从文件中导入数据。所以当 `DataManager` 的实例被创建时,没必要创建一个 `DataImporter` 的实例,更明智的做法是第一次用到 `DataImporter` 的时候才去创建它。
|
`DataManager` 管理数据时也可能不从文件中导入数据。所以当 `DataManager` 的实例被创建时,没必要创建一个 `DataImporter` 的实例,更明智的做法是第一次用到 `DataImporter` 的时候才去创建它。
|
||||||
|
|
||||||
由于使用了 `lazy` ,`importer` 属性只有在第一次被访问的时候才被创建。比如访问它的属性 `fileName` 时:
|
由于使用了 `lazy`,`importer` 属性只有在第一次被访问的时候才被创建。比如访问它的属性 `fileName` 时:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
print(manager.importer.fileName)
|
print(manager.importer.fileName)
|
||||||
@ -178,13 +178,13 @@ print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
|
|||||||
- `Size` 封装了一个 `width` 和一个 `height`
|
- `Size` 封装了一个 `width` 和一个 `height`
|
||||||
- `Rect` 表示一个有原点和尺寸的矩形
|
- `Rect` 表示一个有原点和尺寸的矩形
|
||||||
|
|
||||||
`Rect`也提供了一个名为`center` 的计算属性。一个矩形的中心点可以从原点(`origin`)和大小(`size`)算出,所以不需要将它以显式声明的 `Point` 来保存。`Rect` 的计算属性 `center` 提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。
|
`Rect` 也提供了一个名为 `center` 的计算属性。一个矩形的中心点可以从原点(`origin`)和大小(`size`)算出,所以不需要将它以显式声明的 `Point` 来保存。`Rect` 的计算属性 `center` 提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。
|
||||||
|
|
||||||
上述例子中创建了一个名为 `square` 的 `Rect` 实例,初始值原点是 `(0, 0)`,宽度高度都是 `10`。如下图中蓝色正方形所示。
|
上述例子中创建了一个名为 `square` 的 `Rect` 实例,初始值原点是 `(0, 0)`,宽度高度都是 `10`。如下图中蓝色正方形所示。
|
||||||
|
|
||||||
`square` 的 `center` 属性可以通过点运算符(`square.center`)来访问,这会调用该属性的 getter 来获取它的值。跟直接返回已经存在的值不同,getter 实际上通过计算然后返回一个新的 `Point` 来表示 `square` 的中心点。如代码所示,它正确返回了中心点 `(5, 5)`。
|
`square` 的 `center` 属性可以通过点运算符(`square.center`)来访问,这会调用该属性的 getter 来获取它的值。跟直接返回已经存在的值不同,getter 实际上通过计算然后返回一个新的 `Point` 来表示 `square` 的中心点。如代码所示,它正确返回了中心点 `(5, 5)`。
|
||||||
|
|
||||||
`center` 属性之后被设置了一个新的值 `(15, 15)`,表示向右上方移动正方形到如下图橙色正方形所示的位置。设置属性`center`的值会调用它的 setter 来修改属性 `origin` 的 `x` 和 `y` 的值,从而实现移动正方形到新的位置。
|
`center` 属性之后被设置了一个新的值 `(15, 15)`,表示向右上方移动正方形到如下图橙色正方形所示的位置。设置属性 `center` 的值会调用它的 setter 来修改属性 `origin` 的 `x` 和 `y` 的值,从而实现移动正方形到新的位置。
|
||||||
|
|
||||||
<img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/computedProperties_2x.png" alt="Computed Properties sample" width="388" height="387" />
|
<img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/computedProperties_2x.png" alt="Computed Properties sample" width="388" height="387" />
|
||||||
|
|
||||||
@ -308,7 +308,7 @@ stepCounter.totalSteps = 896
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`lazy`修饰符。
|
> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记 `lazy` 修饰符。
|
||||||
>
|
>
|
||||||
> 局部范围的常量或变量从不延迟计算。
|
> 局部范围的常量或变量从不延迟计算。
|
||||||
|
|
||||||
@ -410,7 +410,7 @@ struct AudioChannel {
|
|||||||
|
|
||||||
结构 `AudioChannel` 定义了 2 个存储型类型属性来实现上述功能。第一个是 `thresholdLevel`,表示音量的最大上限阈值,它是一个值为 `10` 的常量,对所有实例都可见,如果音量高于 `10`,则取最大上限值 `10`(见后面描述)。
|
结构 `AudioChannel` 定义了 2 个存储型类型属性来实现上述功能。第一个是 `thresholdLevel`,表示音量的最大上限阈值,它是一个值为 `10` 的常量,对所有实例都可见,如果音量高于 `10`,则取最大上限值 `10`(见后面描述)。
|
||||||
|
|
||||||
第二个类型属性是变量存储型属性 `maxInputLevelForAllChannels`,它用来表示所有 `AudioChannel` 实例的最大音量,初始值是`0`。
|
第二个类型属性是变量存储型属性 `maxInputLevelForAllChannels`,它用来表示所有 `AudioChannel` 实例的最大音量,初始值是 `0`。
|
||||||
|
|
||||||
`AudioChannel` 也定义了一个名为 `currentLevel` 的存储型实例属性,表示当前声道现在的音量,取值为 `0` 到 `10`。
|
`AudioChannel` 也定义了一个名为 `currentLevel` 的存储型实例属性,表示当前声道现在的音量,取值为 `0` 到 `10`。
|
||||||
|
|
||||||
|
|||||||
@ -10,9 +10,10 @@
|
|||||||
|
|
||||||
> 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
|
||||||
|
|
||||||
> 3.0.1,shanks,2016-11-13
|
> 3.0.1,shanks,2016-11-13
|
||||||
|
|
||||||
> 4.0
|
> 4.0
|
||||||
@ -37,7 +38,7 @@
|
|||||||
|
|
||||||
实例方法要写在它所属的类型的前后大括号之间。实例方法能够隐式访问它所属类型的所有的其他实例方法和属性。实例方法只能被它所属的类的某个特定实例调用。实例方法不能脱离于现存的实例而被调用。
|
实例方法要写在它所属的类型的前后大括号之间。实例方法能够隐式访问它所属类型的所有的其他实例方法和属性。实例方法只能被它所属的类的某个特定实例调用。实例方法不能脱离于现存的实例而被调用。
|
||||||
|
|
||||||
下面的例子,定义一个很简单的`Counter`类,`Counter`能被用来对一个动作发生的次数进行计数:
|
下面的例子,定义一个很简单的 `Counter` 类,`Counter` 能被用来对一个动作发生的次数进行计数:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Counter {
|
class Counter {
|
||||||
@ -54,12 +55,12 @@ class Counter {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`Counter`类定义了三个实例方法:
|
`Counter` 类定义了三个实例方法:
|
||||||
- `increment`让计数器按一递增;
|
- `increment` 让计数器按一递增;
|
||||||
- `increment(by: Int)`让计数器按一个指定的整数值递增;
|
- `increment(by: Int)` 让计数器按一个指定的整数值递增;
|
||||||
- `reset`将计数器重置为0。
|
- `reset` 将计数器重置为0。
|
||||||
|
|
||||||
`Counter`这个类还声明了一个可变属性`count`,用它来保持对当前计数器值的追踪。
|
`Counter` 这个类还声明了一个可变属性 `count`,用它来保持对当前计数器值的追踪。
|
||||||
|
|
||||||
和调用属性一样,用点语法(dot syntax)调用实例方法:
|
和调用属性一样,用点语法(dot syntax)调用实例方法:
|
||||||
|
|
||||||
@ -79,9 +80,9 @@ counter.reset()
|
|||||||
<a name="the_self_property"></a>
|
<a name="the_self_property"></a>
|
||||||
### self 属性
|
### self 属性
|
||||||
|
|
||||||
类型的每一个实例都有一个隐含属性叫做`self`,`self`完全等同于该实例本身。你可以在一个实例的实例方法中使用这个隐含的`self`属性来引用当前实例。
|
类型的每一个实例都有一个隐含属性叫做 `self`,`self` 完全等同于该实例本身。你可以在一个实例的实例方法中使用这个隐含的 `self` 属性来引用当前实例。
|
||||||
|
|
||||||
上面例子中的`increment`方法还可以这样写:
|
上面例子中的 `increment` 方法还可以这样写:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func increment() {
|
func increment() {
|
||||||
@ -89,11 +90,11 @@ func increment() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
实际上,你不必在你的代码里面经常写`self`。不论何时,只要在一个方法中使用一个已知的属性或者方法名称,如果你没有明确地写`self`,Swift 假定你是指当前实例的属性或者方法。这种假定在上面的`Counter`中已经示范了:`Counter`中的三个实例方法中都使用的是`count`(而不是`self.count`)。
|
实际上,你不必在你的代码里面经常写 `self`。不论何时,只要在一个方法中使用一个已知的属性或者方法名称,如果你没有明确地写 `self`,Swift 假定你是指当前实例的属性或者方法。这种假定在上面的 `Counter` 中已经示范了:`Counter` 中的三个实例方法中都使用的是 `count`(而不是 `self.count`)。
|
||||||
|
|
||||||
使用这条规则的主要场景是实例方法的某个参数名称与实例的某个属性名称相同的时候。在这种情况下,参数名称享有优先权,并且在引用属性时必须使用一种更严格的方式。这时你可以使用`self`属性来区分参数名称和属性名称。
|
使用这条规则的主要场景是实例方法的某个参数名称与实例的某个属性名称相同的时候。在这种情况下,参数名称享有优先权,并且在引用属性时必须使用一种更严格的方式。这时你可以使用 `self` 属性来区分参数名称和属性名称。
|
||||||
|
|
||||||
下面的例子中,`self`消除方法参数`x`和实例属性`x`之间的歧义:
|
下面的例子中,`self` 消除方法参数 `x` 和实例属性 `x` 之间的歧义:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct Point {
|
struct Point {
|
||||||
@ -109,16 +110,16 @@ if somePoint.isToTheRightOfX(1.0) {
|
|||||||
// 打印 "This point is to the right of the line where x == 1.0"
|
// 打印 "This point is to the right of the line where x == 1.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
如果不使用`self`前缀,Swift 就认为两次使用的`x`都指的是名称为`x`的函数参数。
|
如果不使用 `self` 前缀,Swift 就认为两次使用的 `x` 都指的是名称为 `x` 的函数参数。
|
||||||
|
|
||||||
<a name="modifying_value_types_from_within_instance_methods"></a>
|
<a name="modifying_value_types_from_within_instance_methods"></a>
|
||||||
### 在实例方法中修改值类型
|
### 在实例方法中修改值类型
|
||||||
|
|
||||||
结构体和枚举是*值类型*。默认情况下,值类型的属性不能在它的实例方法中被修改。
|
结构体和枚举是*值类型*。默认情况下,值类型的属性不能在它的实例方法中被修改。
|
||||||
|
|
||||||
但是,如果你确实需要在某个特定的方法中修改结构体或者枚举的属性,你可以为这个方法选择`可变(mutating)`行为,然后就可以从其方法内部改变它的属性;并且这个方法做的任何改变都会在方法执行结束时写回到原始结构中。方法还可以给它隐含的`self`属性赋予一个全新的实例,这个新实例在方法结束时会替换现存实例。
|
但是,如果你确实需要在某个特定的方法中修改结构体或者枚举的属性,你可以为这个方法选择 `可变(mutating)`行为,然后就可以从其方法内部改变它的属性;并且这个方法做的任何改变都会在方法执行结束时写回到原始结构中。方法还可以给它隐含的 `self` 属性赋予一个全新的实例,这个新实例在方法结束时会替换现存实例。
|
||||||
|
|
||||||
要使用`可变`方法,将关键字`mutating` 放到方法的`func`关键字之前就可以了:
|
要使用 `可变`方法,将关键字 `mutating` 放到方法的 `func` 关键字之前就可以了:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct Point {
|
struct Point {
|
||||||
@ -134,7 +135,7 @@ print("The point is now at (\(somePoint.x), \(somePoint.y))")
|
|||||||
// 打印 "The point is now at (3.0, 4.0)"
|
// 打印 "The point is now at (3.0, 4.0)"
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的`Point`结构体定义了一个可变方法 `moveByX(_:y:)` 来移动`Point`实例到给定的位置。该方法被调用时修改了这个点,而不是返回一个新的点。方法定义时加上了`mutating`关键字,从而允许修改属性。
|
上面的 `Point` 结构体定义了一个可变方法 `moveByX(_:y:)` 来移动 `Point` 实例到给定的位置。该方法被调用时修改了这个点,而不是返回一个新的点。方法定义时加上了 `mutating` 关键字,从而允许修改属性。
|
||||||
|
|
||||||
注意,不能在结构体类型的常量(a constant of structure type)上调用可变方法,因为其属性不能被改变,即使属性是变量属性,详情参见[常量结构体的存储属性](./10_Properties.html#stored_properties_of_constant_structure_instances):
|
注意,不能在结构体类型的常量(a constant of structure type)上调用可变方法,因为其属性不能被改变,即使属性是变量属性,详情参见[常量结构体的存储属性](./10_Properties.html#stored_properties_of_constant_structure_instances):
|
||||||
|
|
||||||
@ -147,7 +148,7 @@ fixedPoint.moveByX(2.0, y: 3.0)
|
|||||||
<a name="assigning_to_self_within_a_mutating_method"></a>
|
<a name="assigning_to_self_within_a_mutating_method"></a>
|
||||||
### 在可变方法中给 self 赋值
|
### 在可变方法中给 self 赋值
|
||||||
|
|
||||||
可变方法能够赋给隐含属性`self`一个全新的实例。上面`Point`的例子可以用下面的方式改写:
|
可变方法能够赋给隐含属性 `self` 一个全新的实例。上面 `Point` 的例子可以用下面的方式改写:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct Point {
|
struct Point {
|
||||||
@ -158,9 +159,9 @@ struct Point {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
新版的可变方法` moveBy(x:y:)`创建了一个新的结构体实例,它的 x 和 y 的值都被设定为目标值。调用这个版本的方法和调用上个版本的最终结果是一样的。
|
新版的可变方法 `moveBy(x:y:)` 创建了一个新的结构体实例,它的 x 和 y 的值都被设定为目标值。调用这个版本的方法和调用上个版本的最终结果是一样的。
|
||||||
|
|
||||||
枚举的可变方法可以把`self`设置为同一枚举类型中不同的成员:
|
枚举的可变方法可以把 `self` 设置为同一枚举类型中不同的成员:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
enum TriStateSwitch {
|
enum TriStateSwitch {
|
||||||
@ -183,18 +184,18 @@ ovenLight.next()
|
|||||||
// ovenLight 现在等于 .Off
|
// ovenLight 现在等于 .Off
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的例子中定义了一个三态开关的枚举。每次调用`next()`方法时,开关在不同的电源状态(`Off`,`Low`,`High`)之间循环切换。
|
上面的例子中定义了一个三态开关的枚举。每次调用 `next()` 方法时,开关在不同的电源状态(`Off`,`Low`,`High`)之间循环切换。
|
||||||
|
|
||||||
<a name="type_methods"></a>
|
<a name="type_methods"></a>
|
||||||
## 类型方法
|
## 类型方法
|
||||||
|
|
||||||
实例方法是被某个类型的实例调用的方法。你也可以定义在类型本身上调用的方法,这种方法就叫做*类型方法*。在方法的`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` 类上调用类型方法的例子:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class SomeClass {
|
class SomeClass {
|
||||||
@ -205,13 +206,13 @@ class SomeClass {
|
|||||||
SomeClass.someTypeMethod()
|
SomeClass.someTypeMethod()
|
||||||
```
|
```
|
||||||
|
|
||||||
在类型方法的方法体(body)中,`self`指向这个类型本身,而不是类型的某个实例。这意味着你可以用`self`来消除类型属性和类型方法参数之间的歧义(类似于我们在前面处理实例属性和实例方法参数时做的那样)。
|
在类型方法的方法体(body)中,`self` 指向这个类型本身,而不是类型的某个实例。这意味着你可以用 `self` 来消除类型属性和类型方法参数之间的歧义(类似于我们在前面处理实例属性和实例方法参数时做的那样)。
|
||||||
|
|
||||||
一般来说,在类型方法的方法体中,任何未限定的方法和属性名称,可以被本类中其他的类型方法和类型属性引用。一个类型方法可以直接通过类型方法的名称调用本类中的其它类型方法,而无需在方法名称前面加上类型名称。类似地,在结构体和枚举中,也能够直接通过类型属性的名称访问本类中的类型属性,而不需要前面加上类型名称。
|
一般来说,在类型方法的方法体中,任何未限定的方法和属性名称,可以被本类中其他的类型方法和类型属性引用。一个类型方法可以直接通过类型方法的名称调用本类中的其它类型方法,而无需在方法名称前面加上类型名称。类似地,在结构体和枚举中,也能够直接通过类型属性的名称访问本类中的类型属性,而不需要前面加上类型名称。
|
||||||
|
|
||||||
下面的例子定义了一个名为`LevelTracker`结构体。它监测玩家的游戏发展情况(游戏的不同层次或阶段)。这是一个单人游戏,但也可以存储多个玩家在同一设备上的游戏信息。
|
下面的例子定义了一个名为 `LevelTracker` 结构体。它监测玩家的游戏发展情况(游戏的不同层次或阶段)。这是一个单人游戏,但也可以存储多个玩家在同一设备上的游戏信息。
|
||||||
|
|
||||||
游戏初始时,所有的游戏等级(除了等级 1)都被锁定。每次有玩家完成一个等级,这个等级就对这个设备上的所有玩家解锁。`LevelTracker`结构体用类型属性和方法监测游戏的哪个等级已经被解锁。它还监测每个玩家的当前等级。
|
游戏初始时,所有的游戏等级(除了等级 1)都被锁定。每次有玩家完成一个等级,这个等级就对这个设备上的所有玩家解锁。`LevelTracker` 结构体用类型属性和方法监测游戏的哪个等级已经被解锁。它还监测每个玩家的当前等级。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct LevelTracker {
|
struct LevelTracker {
|
||||||
@ -238,15 +239,15 @@ struct LevelTracker {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`LevelTracker`监测玩家已解锁的最高等级。这个值被存储在类型属性`highestUnlockedLevel`中。
|
`LevelTracker` 监测玩家已解锁的最高等级。这个值被存储在类型属性 `highestUnlockedLevel` 中。
|
||||||
|
|
||||||
`LevelTracker`还定义了两个类型方法与`highestUnlockedLevel`配合工作。第一个类型方法是`unlock(_:)`,一旦新等级被解锁,它会更新`highestUnlockedLevel`的值。第二个类型方法是`isUnlocked(_:)`,如果某个给定的等级已经被解锁,它将返回`true`。(注意,尽管我们没有使用类似`LevelTracker.highestUnlockedLevel`的写法,这个类型方法还是能够访问类型属性`highestUnlockedLevel`)
|
`LevelTracker` 还定义了两个类型方法与 `highestUnlockedLevel` 配合工作。第一个类型方法是 `unlock(_:)`,一旦新等级被解锁,它会更新 `highestUnlockedLevel` 的值。第二个类型方法是 `isUnlocked(_:)`,如果某个给定的等级已经被解锁,它将返回 `true`。(注意,尽管我们没有使用类似 `LevelTracker.highestUnlockedLevel` 的写法,这个类型方法还是能够访问类型属性 `highestUnlockedLevel`)
|
||||||
|
|
||||||
除了类型属性和类型方法,`LevelTracker`还监测每个玩家的进度。它用实例属性`currentLevel`来监测每个玩家当前的等级。
|
除了类型属性和类型方法,`LevelTracker` 还监测每个玩家的进度。它用实例属性 `currentLevel` 来监测每个玩家当前的等级。
|
||||||
|
|
||||||
为了便于管理`currentLevel`属性,`LevelTracker`定义了实例方法`advance(to:)`。这个方法会在更新`currentLevel`之前检查所请求的新等级是否已经解锁。`advance(to:)`方法返回布尔值以指示是否能够设置`currentLevel`。因为允许在调用`advance(to:)`时候忽略返回值,不会产生编译警告,所以函数被标注为`@ discardableResult`属性,更多关于属性信息,请参考[属性](../chapter3/07_Attributes.html)章节。
|
为了便于管理 `currentLevel` 属性,`LevelTracker` 定义了实例方法 `advance(to:)`。这个方法会在更新 `currentLevel` 之前检查所请求的新等级是否已经解锁。`advance(to:)` 方法返回布尔值以指示是否能够设置 `currentLevel`。因为允许在调用 `advance(to:)` 时候忽略返回值,不会产生编译警告,所以函数被标注为 `@ discardableResult` 属性,更多关于属性信息,请参考[属性](../chapter3/07_Attributes.html)章节。
|
||||||
|
|
||||||
下面,`Player`类使用`LevelTracker`来监测和更新每个玩家的发展进度:
|
下面,`Player` 类使用 `LevelTracker` 来监测和更新每个玩家的发展进度:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Player {
|
class Player {
|
||||||
@ -262,9 +263,9 @@ class Player {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`Player`类创建一个新的`LevelTracker`实例来监测这个用户的进度。它提供了`complete(level:)`方法,一旦玩家完成某个指定等级就调用它。这个方法为所有玩家解锁下一等级,并且将当前玩家的进度更新为下一等级。(我们忽略了`advance(to:)`返回的布尔值,因为之前调用`LevelTracker.unlock(_:)`时就知道了这个等级已经被解锁了)。
|
`Player` 类创建一个新的 `LevelTracker` 实例来监测这个用户的进度。它提供了 `complete(level:)` 方法,一旦玩家完成某个指定等级就调用它。这个方法为所有玩家解锁下一等级,并且将当前玩家的进度更新为下一等级。(我们忽略了 `advance(to:)` 返回的布尔值,因为之前调用 `LevelTracker.unlock(_:)` 时就知道了这个等级已经被解锁了)。
|
||||||
|
|
||||||
你还可以为一个新的玩家创建一个`Player`的实例,然后看这个玩家完成等级一时发生了什么:
|
你还可以为一个新的玩家创建一个 `Player` 的实例,然后看这个玩家完成等级一时发生了什么:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var player = Player(name: "Argyrios")
|
var player = Player(name: "Argyrios")
|
||||||
|
|||||||
@ -27,14 +27,14 @@
|
|||||||
- [下标用法](#subscript_usage)
|
- [下标用法](#subscript_usage)
|
||||||
- [下标选项](#subscript_options)
|
- [下标选项](#subscript_options)
|
||||||
|
|
||||||
*下标*可以定义在类、结构体和枚举中,是访问集合、列表或序列中元素的快捷方式。可以使用下标的索引,设置和获取值,而不需要再调用对应的存取方法。举例来说,用下标访问一个`Array`实例中的元素可以写作`someArray[index]`,访问`Dictionary`实例中的元素可以写作`someDictionary[key]`。
|
*下标*可以定义在类、结构体和枚举中,是访问集合、列表或序列中元素的快捷方式。可以使用下标的索引,设置和获取值,而不需要再调用对应的存取方法。举例来说,用下标访问一个 `Array` 实例中的元素可以写作 `someArray[index]`,访问 `Dictionary` 实例中的元素可以写作 `someDictionary[key]`。
|
||||||
|
|
||||||
一个类型可以定义多个下标,通过不同索引类型进行重载。下标不限于一维,你可以定义具有多个入参的下标满足自定义类型的需求。
|
一个类型可以定义多个下标,通过不同索引类型进行重载。下标不限于一维,你可以定义具有多个入参的下标满足自定义类型的需求。
|
||||||
|
|
||||||
<a name="subscript_syntax"></a>
|
<a name="subscript_syntax"></a>
|
||||||
## 下标语法
|
## 下标语法
|
||||||
|
|
||||||
下标允许你通过在实例名称后面的方括号中传入一个或者多个索引值来对实例进行存取。语法类似于实例方法语法和计算型属性语法的混合。与定义实例方法类似,定义下标使用`subscript`关键字,指定一个或多个输入参数和返回类型;与实例方法不同的是,下标可以设定为读写或只读。这种行为由 getter 和 setter 实现,有点类似计算型属性:
|
下标允许你通过在实例名称后面的方括号中传入一个或者多个索引值来对实例进行存取。语法类似于实例方法语法和计算型属性语法的混合。与定义实例方法类似,定义下标使用 `subscript` 关键字,指定一个或多个输入参数和返回类型;与实例方法不同的是,下标可以设定为读写或只读。这种行为由 getter 和 setter 实现,有点类似计算型属性:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
subscript(index: Int) -> Int {
|
subscript(index: Int) -> Int {
|
||||||
@ -48,9 +48,9 @@ subscript(index: Int) -> Int {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`newValue`的类型和下标的返回类型相同。如同计算型属性,可以不指定 setter 的参数(`newValue`)。如果不指定参数,setter 会提供一个名为`newValue`的默认参数。
|
`newValue` 的类型和下标的返回类型相同。如同计算型属性,可以不指定 setter 的参数(`newValue`)。如果不指定参数,setter 会提供一个名为 `newValue` 的默认参数。
|
||||||
|
|
||||||
如同只读计算型属性,可以省略只读下标的`get`关键字:
|
如同只读计算型属性,可以省略只读下标的 `get` 关键字:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
subscript(index: Int) -> Int {
|
subscript(index: Int) -> Int {
|
||||||
@ -58,7 +58,7 @@ subscript(index: Int) -> Int {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
下面代码演示了只读下标的实现,这里定义了一个`TimesTable`结构体,用来表示传入整数的乘法表:
|
下面代码演示了只读下标的实现,这里定义了一个 `TimesTable` 结构体,用来表示传入整数的乘法表:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct TimesTable {
|
struct TimesTable {
|
||||||
@ -72,33 +72,33 @@ print("six times three is \(threeTimesTable[6])")
|
|||||||
// 打印 "six times three is 18"
|
// 打印 "six times three is 18"
|
||||||
```
|
```
|
||||||
|
|
||||||
在上例中,创建了一个`TimesTable`实例,用来表示整数`3`的乘法表。数值`3`被传递给结构体的构造函数,作为实例成员`multiplier`的值。
|
在上例中,创建了一个 `TimesTable` 实例,用来表示整数 `3` 的乘法表。数值 `3` 被传递给结构体的构造函数,作为实例成员 `multiplier` 的值。
|
||||||
|
|
||||||
你可以通过下标访问`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>
|
||||||
## 下标用法
|
## 下标用法
|
||||||
|
|
||||||
下标的确切含义取决于使用场景。下标通常作为访问集合,列表或序列中元素的快捷方式。你可以针对自己特定的类或结构体的功能来自由地以最恰当的方式实现下标。
|
下标的确切含义取决于使用场景。下标通常作为访问集合,列表或序列中元素的快捷方式。你可以针对自己特定的类或结构体的功能来自由地以最恰当的方式实现下标。
|
||||||
|
|
||||||
例如,Swift 的`Dictionary`类型实现下标用于对其实例中储存的值进行存取操作。为字典设值时,在下标中使用和字典的键类型相同的键,并把一个和字典的值类型相同的值赋给这个下标:
|
例如,Swift 的 `Dictionary` 类型实现下标用于对其实例中储存的值进行存取操作。为字典设值时,在下标中使用和字典的键类型相同的键,并把一个和字典的值类型相同的值赋给这个下标:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
|
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
|
||||||
numberOfLegs["bird"] = 2
|
numberOfLegs["bird"] = 2
|
||||||
```
|
```
|
||||||
|
|
||||||
上例定义一个名为`numberOfLegs`的变量,并用一个包含三对键值的字典字面量初始化它。`numberOfLegs`字典的类型被推断为`[String: Int]`。字典创建完成后,该例子通过下标将`String`类型的键`bird`和`Int`类型的值`2`添加到字典中。
|
上例定义一个名为 `numberOfLegs` 的变量,并用一个包含三对键值的字典字面量初始化它。`numberOfLegs` 字典的类型被推断为 `[String: Int]`。字典创建完成后,该例子通过下标将 `String` 类型的键 `bird` 和 `Int` 类型的值 `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>
|
||||||
## 下标选项
|
## 下标选项
|
||||||
@ -107,7 +107,7 @@ numberOfLegs["bird"] = 2
|
|||||||
|
|
||||||
一个类或结构体可以根据自身需要提供多个下标实现,使用下标时将通过入参的数量和类型进行区分,自动匹配合适的下标,这就是*下标的重载*。
|
一个类或结构体可以根据自身需要提供多个下标实现,使用下标时将通过入参的数量和类型进行区分,自动匹配合适的下标,这就是*下标的重载*。
|
||||||
|
|
||||||
虽然接受单一入参的下标是最常见的,但也可以根据情况定义接受多个入参的下标。例如下例定义了一个`Matrix`结构体,用于表示一个`Double`类型的二维矩阵。`Matrix`结构体的下标接受两个整型参数:
|
虽然接受单一入参的下标是最常见的,但也可以根据情况定义接受多个入参的下标。例如下例定义了一个 `Matrix` 结构体,用于表示一个 `Double` 类型的二维矩阵。`Matrix` 结构体的下标接受两个整型参数:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct Matrix {
|
struct Matrix {
|
||||||
@ -134,30 +134,30 @@ struct Matrix {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`Matrix`提供了一个接受两个入参的构造方法,入参分别是`rows`和`columns`,创建了一个足够容纳`rows * columns`个`Double`类型的值的数组。通过传入数组长度和初始值`0.0`到数组的构造器,将矩阵中每个位置的值初始化为`0.0`。关于数组的这种构造方法请参考[创建一个带有默认值的数组](./04_Collection_Types.html#creating_an_array_with_a_default_value)。
|
`Matrix` 提供了一个接受两个入参的构造方法,入参分别是 `rows` 和 `columns`,创建了一个足够容纳 `rows * columns` 个 `Double` 类型的值的数组。通过传入数组长度和初始值 `0.0` 到数组的构造器,将矩阵中每个位置的值初始化为 `0.0`。关于数组的这种构造方法请参考[创建一个带有默认值的数组](./04_Collection_Types.html#creating_an_array_with_a_default_value)。
|
||||||
|
|
||||||
你可以通过传入合适的`row`和`column`的数量来构造一个新的`Matrix`实例:
|
你可以通过传入合适的 `row` 和 `column` 的数量来构造一个新的 `Matrix` 实例:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var matrix = Matrix(rows: 2, columns: 2)
|
var matrix = Matrix(rows: 2, columns: 2)
|
||||||
```
|
```
|
||||||
|
|
||||||
上例中创建了一个`Matrix`实例来表示两行两列的矩阵。该`Matrix`实例的`grid`数组按照从左上到右下的阅读顺序将矩阵扁平化存储:
|
上例中创建了一个 `Matrix` 实例来表示两行两列的矩阵。该 `Matrix` 实例的 `grid` 数组按照从左上到右下的阅读顺序将矩阵扁平化存储:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
将`row`和`column`的值传入下标来为矩阵设值,下标的入参使用逗号分隔:
|
将 `row` 和 `column` 的值传入下标来为矩阵设值,下标的入参使用逗号分隔:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
matrix[0, 1] = 1.5
|
matrix[0, 1] = 1.5
|
||||||
matrix[1, 0] = 3.2
|
matrix[1, 0] = 3.2
|
||||||
```
|
```
|
||||||
|
|
||||||
上面两条语句分别调用下标的 setter 将矩阵右上角位置(即`row`为`0`、`column`为`1`的位置)的值设置为`1.5`,将矩阵左下角位置(即`row`为`1`、`column`为`0`的位置)的值设置为`3.2`:
|
上面两条语句分别调用下标的 setter 将矩阵右上角位置(即 `row` 为 `0`、`column` 为 `1` 的位置)的值设置为 `1.5`,将矩阵左下角位置(即 `row` 为 `1`、`column` 为 `0` 的位置)的值设置为 `3.2`:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
`Matrix`下标的 getter 和 setter 中都含有断言,用来检查下标入参`row`和`column`的值是否有效。为了方便进行断言,`Matrix`包含了一个名为`indexIsValid(row:column:)`的便利方法,用来检查入参`row`和`column`的值是否在矩阵范围内:
|
`Matrix` 下标的 getter 和 setter 中都含有断言,用来检查下标入参 `row` 和 `column` 的值是否有效。为了方便进行断言,`Matrix` 包含了一个名为 `indexIsValid(row:column:)` 的便利方法,用来检查入参 `row` 和 `column` 的值是否在矩阵范围内:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func indexIsValid(row: Int, column: Int) -> Bool {
|
func indexIsValid(row: Int, column: Int) -> Bool {
|
||||||
|
|||||||
@ -7,9 +7,10 @@
|
|||||||
|
|
||||||
> 2.0,2.1
|
> 2.0,2.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.1,shanks,2016-11-13
|
> 3.0.1,shanks,2016-11-13
|
||||||
|
|
||||||
> 4.0
|
> 4.0
|
||||||
@ -40,9 +41,9 @@
|
|||||||
>
|
>
|
||||||
> Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。
|
> Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。
|
||||||
|
|
||||||
下面的例子定义了一个叫`Vehicle`的基类。这个基类声明了一个名为`currentSpeed `,默认值是`0.0`的存储属性(属性类型推断为`Double`)。`currentSpeed`属性的值被一个`String`类型的只读计算型属性`description`使用,用来创建车辆的描述。
|
下面的例子定义了一个叫 `Vehicle` 的基类。这个基类声明了一个名为 `currentSpeed`,默认值是 `0.0` 的存储属性(属性类型推断为 `Double`)。`currentSpeed` 属性的值被一个 `String` 类型的只读计算型属性 `description` 使用,用来创建车辆的描述。
|
||||||
|
|
||||||
`Vehicle`基类也定义了一个名为`makeNoise`的方法。这个方法实际上不为`Vehicle`实例做任何事,但之后将会被`Vehicle`的子类定制:
|
`Vehicle` 基类也定义了一个名为 `makeNoise` 的方法。这个方法实际上不为 `Vehicle` 实例做任何事,但之后将会被 `Vehicle` 的子类定制:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Vehicle {
|
class Vehicle {
|
||||||
@ -56,20 +57,20 @@ class Vehicle {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
您可以用初始化语法创建一个`Vehicle`的新实例,即类名后面跟一个空括号:
|
您可以用初始化语法创建一个 `Vehicle` 的新实例,即类名后面跟一个空括号:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let someVehicle = Vehicle()
|
let someVehicle = Vehicle()
|
||||||
```
|
```
|
||||||
|
|
||||||
现在已经创建了一个`Vehicle`的新实例,你可以访问它的`description`属性来打印车辆的当前速度:
|
现在已经创建了一个 `Vehicle` 的新实例,你可以访问它的 `description` 属性来打印车辆的当前速度:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
print("Vehicle: \(someVehicle.description)")
|
print("Vehicle: \(someVehicle.description)")
|
||||||
// 打印 "Vehicle: traveling at 0.0 miles per hour"
|
// 打印 "Vehicle: traveling at 0.0 miles per hour"
|
||||||
```
|
```
|
||||||
|
|
||||||
`Vehicle`类定义了一个通用特性的车辆类,实际上没什么用处。为了让它变得更加有用,需要完善它从而能够描述一个更加具体类型的车辆。
|
`Vehicle` 类定义了一个通用特性的车辆类,实际上没什么用处。为了让它变得更加有用,需要完善它从而能够描述一个更加具体类型的车辆。
|
||||||
|
|
||||||
<a name="subclassing"></a>
|
<a name="subclassing"></a>
|
||||||
## 子类生成
|
## 子类生成
|
||||||
@ -84,7 +85,7 @@ class SomeClass: SomeSuperclass {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
下一个例子,定义一个叫`Bicycle`的子类,继承成父类`Vehicle`:
|
下一个例子,定义一个叫 `Bicycle` 的子类,继承成父类 `Vehicle`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Bicycle: Vehicle {
|
class Bicycle: Vehicle {
|
||||||
@ -92,18 +93,18 @@ class Bicycle: Vehicle {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
新的`Bicycle`类自动获得`Vehicle`类的所有特性,比如`currentSpeed`和`description`属性,还有它的`makeNoise()`方法。
|
新的 `Bicycle` 类自动获得 `Vehicle` 类的所有特性,比如 `currentSpeed` 和 `description` 属性,还有它的 `makeNoise()` 方法。
|
||||||
|
|
||||||
除了它所继承的特性,`Bicycle`类还定义了一个默认值为`false`的存储型属性`hasBasket`(属性推断为`Bool`)。
|
除了它所继承的特性,`Bicycle` 类还定义了一个默认值为 `false` 的存储型属性 `hasBasket`(属性推断为 `Bool`)。
|
||||||
|
|
||||||
默认情况下,你创建任何新的`Bicycle`实例将不会有一个篮子(即`hasBasket`属性默认为`false`),创建该实例之后,你可以为特定的`Bicycle`实例设置`hasBasket`属性为`ture`:
|
默认情况下,你创建任何新的 `Bicycle` 实例将不会有一个篮子(即 `hasBasket` 属性默认为 `false`),创建该实例之后,你可以为特定的 `Bicycle` 实例设置 `hasBasket` 属性为 `ture`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let bicycle = Bicycle()
|
let bicycle = Bicycle()
|
||||||
bicycle.hasBasket = true
|
bicycle.hasBasket = true
|
||||||
```
|
```
|
||||||
|
|
||||||
你还可以修改`Bicycle`实例所继承的`currentSpeed`属性,和查询实例所继承的`description`属性:
|
你还可以修改 `Bicycle` 实例所继承的 `currentSpeed` 属性,和查询实例所继承的 `description` 属性:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
bicycle.currentSpeed = 15.0
|
bicycle.currentSpeed = 15.0
|
||||||
@ -111,7 +112,7 @@ print("Bicycle: \(bicycle.description)")
|
|||||||
// 打印 "Bicycle: traveling at 15.0 miles per hour"
|
// 打印 "Bicycle: traveling at 15.0 miles per hour"
|
||||||
```
|
```
|
||||||
|
|
||||||
子类还可以继续被其它类继承,下面的示例为`Bicycle`创建了一个名为`Tandem`(双人自行车)的子类:
|
子类还可以继续被其它类继承,下面的示例为 `Bicycle` 创建了一个名为 `Tandem`(双人自行车)的子类:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Tandem: Bicycle {
|
class Tandem: Bicycle {
|
||||||
@ -119,9 +120,9 @@ class Tandem: Bicycle {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`Tandem`从`Bicycle`继承了所有的属性与方法,这又使它同时继承了`Vehicle`的所有属性与方法。`Tandem`也增加了一个新的叫做`currentNumberOfPassengers`的存储型属性,默认值为`0`。
|
`Tandem` 从 `Bicycle` 继承了所有的属性与方法,这又使它同时继承了 `Vehicle` 的所有属性与方法。`Tandem` 也增加了一个新的叫做 `currentNumberOfPassengers` 的存储型属性,默认值为 `0`。
|
||||||
|
|
||||||
如果你创建了一个`Tandem`的实例,你可以使用它所有的新属性和继承的属性,还能查询从`Vehicle`继承来的只读属性`description`:
|
如果你创建了一个 `Tandem` 的实例,你可以使用它所有的新属性和继承的属性,还能查询从 `Vehicle` 继承来的只读属性 `description`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let tandem = Tandem()
|
let tandem = Tandem()
|
||||||
@ -137,25 +138,25 @@ print("Tandem: \(tandem.description)")
|
|||||||
|
|
||||||
子类可以为继承来的实例方法,类方法,实例属性,或下标提供自己定制的实现。我们把这种行为叫*重写*。
|
子类可以为继承来的实例方法,类方法,实例属性,或下标提供自己定制的实现。我们把这种行为叫*重写*。
|
||||||
|
|
||||||
如果要重写某个特性,你需要在重写定义的前面加上`override`关键字。这么做,你就表明了你是想提供一个重写版本,而非错误地提供了一个相同的定义。意外的重写行为可能会导致不可预知的错误,任何缺少`override`关键字的重写都会在编译时被诊断为错误。
|
如果要重写某个特性,你需要在重写定义的前面加上 `override` 关键字。这么做,你就表明了你是想提供一个重写版本,而非错误地提供了一个相同的定义。意外的重写行为可能会导致不可预知的错误,任何缺少 `override` 关键字的重写都会在编译时被诊断为错误。
|
||||||
|
|
||||||
`override`关键字会提醒 Swift 编译器去检查该类的超类(或其中一个父类)是否有匹配重写版本的声明。这个检查可以确保你的重写定义是正确的。
|
`override` 关键字会提醒 Swift 编译器去检查该类的超类(或其中一个父类)是否有匹配重写版本的声明。这个检查可以确保你的重写定义是正确的。
|
||||||
|
|
||||||
### 访问超类的方法,属性及下标
|
### 访问超类的方法,属性及下标
|
||||||
|
|
||||||
当你在子类中重写超类的方法,属性或下标时,有时在你的重写版本中使用已经存在的超类实现会大有裨益。比如,你可以完善已有实现的行为,或在一个继承来的变量中存储一个修改过的值。
|
当你在子类中重写超类的方法,属性或下标时,有时在你的重写版本中使用已经存在的超类实现会大有裨益。比如,你可以完善已有实现的行为,或在一个继承来的变量中存储一个修改过的值。
|
||||||
|
|
||||||
在合适的地方,你可以通过使用`super`前缀来访问超类版本的方法,属性或下标:
|
在合适的地方,你可以通过使用 `super` 前缀来访问超类版本的方法,属性或下标:
|
||||||
|
|
||||||
* 在方法`someMethod()`的重写实现中,可以通过`super.someMethod()`来调用超类版本的`someMethod()`方法。
|
* 在方法 `someMethod()` 的重写实现中,可以通过 `super.someMethod()` 来调用超类版本的 `someMethod()` 方法。
|
||||||
* 在属性`someProperty`的 getter 或 setter 的重写实现中,可以通过`super.someProperty`来访问超类版本的`someProperty`属性。
|
* 在属性 `someProperty` 的 getter 或 setter 的重写实现中,可以通过 `super.someProperty` 来访问超类版本的 `someProperty` 属性。
|
||||||
* 在下标的重写实现中,可以通过`super[someIndex]`来访问超类版本中的相同下标。
|
* 在下标的重写实现中,可以通过 `super[someIndex]` 来访问超类版本中的相同下标。
|
||||||
|
|
||||||
### 重写方法
|
### 重写方法
|
||||||
|
|
||||||
在子类中,你可以重写继承来的实例方法或类方法,提供一个定制或替代的方法实现。
|
在子类中,你可以重写继承来的实例方法或类方法,提供一个定制或替代的方法实现。
|
||||||
|
|
||||||
下面的例子定义了`Vehicle`的一个新的子类,叫`Train`,它重写了从`Vehicle`类继承来的`makeNoise()`方法:
|
下面的例子定义了 `Vehicle` 的一个新的子类,叫 `Train`,它重写了从 `Vehicle` 类继承来的 `makeNoise()` 方法:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Train: Vehicle {
|
class Train: Vehicle {
|
||||||
@ -165,7 +166,7 @@ class Train: Vehicle {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
如果你创建一个`Train`的新实例,并调用了它的`makeNoise()`方法,你就会发现`Train`版本的方法被调用:
|
如果你创建一个 `Train` 的新实例,并调用了它的 `makeNoise()` 方法,你就会发现 `Train` 版本的方法被调用:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let train = Train()
|
let train = Train()
|
||||||
@ -185,9 +186,9 @@ train.makeNoise()
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 如果你在重写属性中提供了 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` 属性,提供包含当前档位的自定义描述:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Car: Vehicle {
|
class Car: Vehicle {
|
||||||
@ -198,9 +199,9 @@ class Car: Vehicle {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
重写的`description`属性首先要调用`super.description`返回`Vehicle`类的`description`属性。之后,`Car`类版本的`description`在末尾增加了一些额外的文本来提供关于当前档位的信息。
|
重写的 `description` 属性首先要调用 `super.description` 返回 `Vehicle` 类的 `description` 属性。之后,`Car` 类版本的 `description` 在末尾增加了一些额外的文本来提供关于当前档位的信息。
|
||||||
|
|
||||||
如果你创建了`Car`的实例并且设置了它的`gear`和`currentSpeed`属性,你可以看到它的`description`返回了`Car`中的自定义描述:
|
如果你创建了 `Car` 的实例并且设置了它的 `gear` 和 `currentSpeed` 属性,你可以看到它的 `description` 返回了 `Car` 中的自定义描述:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let car = Car()
|
let car = Car()
|
||||||
@ -217,10 +218,10 @@ print("Car: \(car.description)")
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值是不可以被设置的,所以,为它们提供`willSet`或`didSet`实现是不恰当。
|
> 你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值是不可以被设置的,所以,为它们提供 `willSet` 或 `didSet` 实现是不恰当。
|
||||||
此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已经为那个属性提供了定制的 setter,那么你在 setter 中就可以观察到任何值变化了。
|
此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已经为那个属性提供了定制的 setter,那么你在 setter 中就可以观察到任何值变化了。
|
||||||
|
|
||||||
下面的例子定义了一个新类叫`AutomaticCar`,它是`Car`的子类。`AutomaticCar`表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位:
|
下面的例子定义了一个新类叫 `AutomaticCar`,它是 `Car` 的子类。`AutomaticCar` 表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class AutomaticCar: Car {
|
class AutomaticCar: Car {
|
||||||
@ -232,7 +233,7 @@ class AutomaticCar: Car {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
无论何时当你设置`AutomaticCar`的`currentSpeed`属性,属性的`didSet`观察器就会自动地设置`gear`属性,为新的速度选择一个合适的挡位。具体来说就是,属性观察器将新的速度值除以`10`,然后向下取得最接近的整数值,最后加`1`来得到档位`gear`的值。例如,速度为`35.0`时,挡位为`4`:
|
无论何时当你设置 `AutomaticCar` 的 `currentSpeed` 属性,属性的 `didSet` 观察器就会自动地设置 `gear` 属性,为新的速度选择一个合适的挡位。具体来说就是,属性观察器将新的速度值除以 `10`,然后向下取得最接近的整数值,最后加 `1` 来得到档位 `gear` 的值。例如,速度为 `35.0` 时,挡位为 `4`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let automatic = AutomaticCar()
|
let automatic = AutomaticCar()
|
||||||
@ -244,8 +245,8 @@ print("AutomaticCar: \(automatic.description)")
|
|||||||
<a name="preventing_overrides"></a>
|
<a name="preventing_overrides"></a>
|
||||||
## 防止重写
|
## 防止重写
|
||||||
|
|
||||||
你可以通过把方法,属性或下标标记为*`final`*来防止它们被重写,只需要在声明关键字前加上`final`修饰符即可(例如:`final var`,`final func`,`final class func`,以及`final subscript`)。
|
你可以通过把方法,属性或下标标记为*`final`*来防止它们被重写,只需要在声明关键字前加上 `final` 修饰符即可(例如:`final var`,`final func`,`final class func`,以及 `final subscript`)。
|
||||||
|
|
||||||
任何试图对带有`final`标记的方法、属性或下标进行重写,都会在编译时会报错。在类扩展中的方法,属性或下标也可以在扩展的定义里标记为 final 的。
|
任何试图对带有 `final` 标记的方法、属性或下标进行重写,都会在编译时会报错。在类扩展中的方法,属性或下标也可以在扩展的定义里标记为 final 的。
|
||||||
|
|
||||||
你可以通过在关键字`class`前添加`final`修饰符(`final class`)来将整个类标记为 final 的。这样的类是不可被继承的,试图继承这样的类会导致编译报错。
|
你可以通过在关键字 `class` 前添加 `final` 修饰符(`final class`)来将整个类标记为 final 的。这样的类是不可被继承的,试图继承这样的类会导致编译报错。
|
||||||
|
|||||||
@ -108,7 +108,7 @@ struct Fahrenheit {
|
|||||||
|
|
||||||
自定义构造过程时,可以在定义中提供*构造参数*,指定参数值的类型和名字。构造参数的功能和语法跟函数和方法的参数相同。
|
自定义构造过程时,可以在定义中提供*构造参数*,指定参数值的类型和名字。构造参数的功能和语法跟函数和方法的参数相同。
|
||||||
|
|
||||||
下面例子中定义了一个包含摄氏度温度的结构体 `Celsius`。它定义了两个不同的构造器:`init(fromFahrenheit:)`和`init(fromKelvin:)`,二者分别通过接受不同温标下的温度值来创建新的实例:
|
下面例子中定义了一个包含摄氏度温度的结构体 `Celsius`。它定义了两个不同的构造器:`init(fromFahrenheit:)` 和 `init(fromKelvin:)`,二者分别通过接受不同温标下的温度值来创建新的实例:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct Celsius {
|
struct Celsius {
|
||||||
@ -127,7 +127,7 @@ let freezingPointOfWater = Celsius(fromKelvin: 273.15)
|
|||||||
// freezingPointOfWater.temperatureInCelsius 是 0.0
|
// freezingPointOfWater.temperatureInCelsius 是 0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
第一个构造器拥有一个构造参数,其外部名字为`fromFahrenheit`,内部名字为`fahrenheit`;第二个构造器也拥有一个构造参数,其外部名字为`fromKelvin`,内部名字为`kelvin`。这两个构造器都将唯一的参数值转换成摄氏温度值,并保存在属性 `temperatureInCelsius` 中。
|
第一个构造器拥有一个构造参数,其外部名字为 `fromFahrenheit`,内部名字为 `fahrenheit`;第二个构造器也拥有一个构造参数,其外部名字为 `fromKelvin`,内部名字为 `kelvin`。这两个构造器都将唯一的参数值转换成摄氏温度值,并保存在属性 `temperatureInCelsius` 中。
|
||||||
|
|
||||||
<a name="parameter_names_and_argument_labels"></a>
|
<a name="parameter_names_and_argument_labels"></a>
|
||||||
### 参数名和参数标签
|
### 参数名和参数标签
|
||||||
@ -138,7 +138,7 @@ let freezingPointOfWater = Celsius(fromKelvin: 273.15)
|
|||||||
|
|
||||||
以下例子中定义了一个结构体 `Color`,它包含了三个常量:`red`、`green` 和 `blue`。这些属性可以存储 `0.0` 到 `1.0` 之间的值,用来指示颜色中红、绿、蓝成分的含量。
|
以下例子中定义了一个结构体 `Color`,它包含了三个常量:`red`、`green` 和 `blue`。这些属性可以存储 `0.0` 到 `1.0` 之间的值,用来指示颜色中红、绿、蓝成分的含量。
|
||||||
|
|
||||||
`Color` 提供了一个构造器,其中包含三个`Double`类型的构造参数。`Color` 也提供了第二个构造器,它只包含名为`white` 的 `Double` 类型的参数,它被用于给上述三个构造参数赋予同样的值。
|
`Color` 提供了一个构造器,其中包含三个 `Double` 类型的构造参数。`Color` 也提供了第二个构造器,它只包含名为 `white` 的 `Double` 类型的参数,它被用于给上述三个构造参数赋予同样的值。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct Color {
|
struct Color {
|
||||||
@ -156,7 +156,7 @@ struct Color {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
两种构造器都能通过提供的初始参数值来创建一个新的`Color`实例:
|
两种构造器都能通过提供的初始参数值来创建一个新的 `Color` 实例:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
|
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
|
||||||
@ -195,12 +195,12 @@ let bodyTemperature = Celsius(37.0)
|
|||||||
// bodyTemperature.temperatureInCelsius 为 37.0
|
// bodyTemperature.temperatureInCelsius 为 37.0
|
||||||
```
|
```
|
||||||
|
|
||||||
调用 `Celsius(37.0)` 意图明确,不需要参数标签。因此适合使用 `init(_ celsius: Double)` 这样的构造器,从而可以通过提供未命名的`Double`值调用构造器,而不需要加上参数标签。
|
调用 `Celsius(37.0)` 意图明确,不需要参数标签。因此适合使用 `init(_ celsius: Double)` 这样的构造器,从而可以通过提供未命名的 `Double` 值调用构造器,而不需要加上参数标签。
|
||||||
|
|
||||||
<a name="optional_property_types"></a>
|
<a name="optional_property_types"></a>
|
||||||
### 可选属性类型
|
### 可选属性类型
|
||||||
|
|
||||||
如果你定制的类型包含一个逻辑上允许取值为空的存储型属性——无论是因为它无法在初始化时赋值,还是因为它在之后某个时间点可以赋值为空——你都需要将它定义为`可选类型`。可选类型的属性将自动初始化为 `nil`,表示这个属性是有意在初始化时设置为空的。
|
如果你定制的类型包含一个逻辑上允许取值为空的存储型属性——无论是因为它无法在初始化时赋值,还是因为它在之后某个时间点可以赋值为空——你都需要将它定义为 `可选类型`。可选类型的属性将自动初始化为 `nil`,表示这个属性是有意在初始化时设置为空的。
|
||||||
|
|
||||||
下面例子中定义了类 `SurveyQuestion`,它包含一个可选字符串属性 `response`:
|
下面例子中定义了类 `SurveyQuestion`,它包含一个可选字符串属性 `response`:
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ cheeseQuestion.ask()
|
|||||||
cheeseQuestion.response = "Yes, I do like cheese."
|
cheeseQuestion.response = "Yes, I do like cheese."
|
||||||
```
|
```
|
||||||
|
|
||||||
调查问题的答案在回答前是无法确定的,因此我们将属性 `response` 声明为 `String?` 类型,或者说是`可选字符串类型`。当 `SurveyQuestion` 实例化时,它将自动赋值为`nil`,表明此字符串暂时还没有值。
|
调查问题的答案在回答前是无法确定的,因此我们将属性 `response` 声明为 `String?` 类型,或者说是 `可选字符串类型`。当 `SurveyQuestion` 实例化时,它将自动赋值为 `nil`,表明此字符串暂时还没有值。
|
||||||
|
|
||||||
<a name="assigning_constant_properties_during_initialization"></a>
|
<a name="assigning_constant_properties_during_initialization"></a>
|
||||||
### 构造过程中常量属性的赋值
|
### 构造过程中常量属性的赋值
|
||||||
@ -233,7 +233,7 @@ cheeseQuestion.response = "Yes, I do like cheese."
|
|||||||
>
|
>
|
||||||
> 对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。
|
> 对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。
|
||||||
|
|
||||||
你可以修改上面的 `SurveyQuestion` 示例,用常量属性替代变量属性 `text`,表示问题内容 `text` 在`SurveyQuestion`的实例被创建之后不会再被修改。尽管 `text` 属性现在是常量,我们仍然可以在类的构造器中设置它的值:
|
你可以修改上面的 `SurveyQuestion` 示例,用常量属性替代变量属性 `text`,表示问题内容 `text` 在 `SurveyQuestion` 的实例被创建之后不会再被修改。尽管 `text` 属性现在是常量,我们仍然可以在类的构造器中设置它的值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class SurveyQuestion {
|
class SurveyQuestion {
|
||||||
@ -268,7 +268,7 @@ class ShoppingListItem {
|
|||||||
var item = ShoppingListItem()
|
var item = ShoppingListItem()
|
||||||
```
|
```
|
||||||
|
|
||||||
由于 `ShoppingListItem` 类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个可以为所有属性设置默认值的默认构造器(尽管代码中没有显式为`name`属性设置默认值,但由于`name`是可选字符串类型,它将默认设置为`nil`)。上面例子中使用默认构造器创造了一个 `ShoppingListItem` 类的实例(使用 `ShoppingListItem()` 形式的构造器语法),并将其赋值给变量 `item`。
|
由于 `ShoppingListItem` 类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个可以为所有属性设置默认值的默认构造器(尽管代码中没有显式为 `name` 属性设置默认值,但由于 `name` 是可选字符串类型,它将默认设置为 `nil`)。上面例子中使用默认构造器创造了一个 `ShoppingListItem` 类的实例(使用 `ShoppingListItem()` 形式的构造器语法),并将其赋值给变量 `item`。
|
||||||
|
|
||||||
<a name="memberwise_initializers_for_structure_types"></a>
|
<a name="memberwise_initializers_for_structure_types"></a>
|
||||||
### 结构体的逐一成员构造器
|
### 结构体的逐一成员构造器
|
||||||
@ -277,7 +277,7 @@ var item = ShoppingListItem()
|
|||||||
|
|
||||||
逐一成员构造器是用来初始化结构体新实例里成员属性的快捷方法。我们在调用逐一成员构造器时,通过与成员属性名相同的参数名进行传值来完成对成员属性的初始赋值。
|
逐一成员构造器是用来初始化结构体新实例里成员属性的快捷方法。我们在调用逐一成员构造器时,通过与成员属性名相同的参数名进行传值来完成对成员属性的初始赋值。
|
||||||
|
|
||||||
下面例子中定义了一个结构体 `Size`,它包含两个属性 `width` 和 `height`。Swift 可以根据这两个属性的初始赋值`0.0` 自动推导出它们的类型为 `Double`。
|
下面例子中定义了一个结构体 `Size`,它包含两个属性 `width` 和 `height`。Swift 可以根据这两个属性的初始赋值 `0.0` 自动推导出它们的类型为 `Double`。
|
||||||
|
|
||||||
结构体 `Size` 自动获得了一个逐一成员构造器 `init(width:height:)`。你可以用它来创建新的 Size 实例:
|
结构体 `Size` 自动获得了一个逐一成员构造器 `init(width:height:)`。你可以用它来创建新的 Size 实例:
|
||||||
|
|
||||||
@ -315,7 +315,7 @@ struct Point {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
你可以通过以下三种方式为 `Rect` 创建实例——使用含有默认值的 `origin` 和 `size` 属性来初始化;提供指定的`origin` 和 `size` 实例来初始化;提供指定的 `center` 和 `size` 来初始化。在下面 `Rect` 结构体定义中,我们为这三种方式提供了三个自定义的构造器:
|
你可以通过以下三种方式为 `Rect` 创建实例——使用含有默认值的 `origin` 和 `size` 属性来初始化;提供指定的 `origin` 和 `size` 实例来初始化;提供指定的 `center` 和 `size` 来初始化。在下面 `Rect` 结构体定义中,我们为这三种方式提供了三个自定义的构造器:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct Rect {
|
struct Rect {
|
||||||
@ -363,7 +363,7 @@ let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 如果你想用另外一种不需要自己定义`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>
|
||||||
## 类的继承和构造过程
|
## 类的继承和构造过程
|
||||||
@ -451,7 +451,7 @@ Swift 中类的构造过程包含两个阶段。第一个阶段,类中的每
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> Swift 的两段式构造过程跟 Objective-C 中的构造过程类似。最主要的区别在于阶段 1,Objective-C 给每一个属性赋值 `0` 或空值(比如说`0`或`nil`)。Swift 的构造流程则更加灵活,它允许你设置定制的初始值,并自如应对某些属性不能以 `0` 或 `nil` 作为合法默认值的情况。
|
> Swift 的两段式构造过程跟 Objective-C 中的构造过程类似。最主要的区别在于阶段 1,Objective-C 给每一个属性赋值 `0` 或空值(比如说 `0` 或 `nil`)。Swift 的构造流程则更加灵活,它允许你设置定制的初始值,并自如应对某些属性不能以 `0` 或 `nil` 作为合法默认值的情况。
|
||||||
|
|
||||||
Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造过程不出错地完成:
|
Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造过程不出错地完成:
|
||||||
|
|
||||||
@ -471,7 +471,7 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
|
|||||||
|
|
||||||
##### 安全检查 4
|
##### 安全检查 4
|
||||||
|
|
||||||
构造器在第一阶段构造完成之前,不能调用任何实例方法,不能读取任何实例属性的值,不能引用`self`作为一个值。
|
构造器在第一阶段构造完成之前,不能调用任何实例方法,不能读取任何实例属性的值,不能引用 `self` 作为一个值。
|
||||||
|
|
||||||
类实例在第一阶段结束以前并不是完全有效的。只有第一阶段完成后,该实例才会成为有效实例,才能访问属性和调用方法。
|
类实例在第一阶段结束以前并不是完全有效的。只有第一阶段完成后,该实例才会成为有效实例,才能访问属性和调用方法。
|
||||||
|
|
||||||
@ -530,7 +530,7 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 当你重写一个父类的指定构造器时,你总是需要写`override`修饰符,即使是为了实现子类的便利构造器。
|
> 当你重写一个父类的指定构造器时,你总是需要写 `override` 修饰符,即使是为了实现子类的便利构造器。
|
||||||
|
|
||||||
相反,如果你编写了一个和父类便利构造器相匹配的子类构造器,由于子类不能直接调用父类的便利构造器(每个规则都在上文[类的构造器代理规则](#initializer_delegation_for_class_types)有所描述),因此,严格意义上来讲,你的子类并未对一个父类构造器提供重写。最后的结果就是,你在子类中“重写”一个父类便利构造器时,不需要加 `override` 修饰符。
|
相反,如果你编写了一个和父类便利构造器相匹配的子类构造器,由于子类不能直接调用父类的便利构造器(每个规则都在上文[类的构造器代理规则](#initializer_delegation_for_class_types)有所描述),因此,严格意义上来讲,你的子类并未对一个父类构造器提供重写。最后的结果就是,你在子类中“重写”一个父类便利构造器时,不需要加 `override` 修饰符。
|
||||||
|
|
||||||
@ -545,7 +545,7 @@ class Vehicle {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`Vehicle` 类只为存储型属性提供默认值,也没有提供自定义构造器。因此,它会自动获得一个默认构造器,具体内容请参考[默认构造器](#default_initializers)。自动获得的默认构造器总是类中的指定构造器,它可以用于创建`numberOfWheels` 为 `0` 的 `Vehicle`
|
`Vehicle` 类只为存储型属性提供默认值,也没有提供自定义构造器。因此,它会自动获得一个默认构造器,具体内容请参考[默认构造器](#default_initializers)。自动获得的默认构造器总是类中的指定构造器,它可以用于创建 `numberOfWheels` 为 `0` 的 `Vehicle`
|
||||||
实例:
|
实例:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
@ -567,7 +567,7 @@ class Bicycle: Vehicle {
|
|||||||
|
|
||||||
子类 `Bicycle` 定义了一个自定义指定构造器 `init()`。这个指定构造器和父类的指定构造器相匹配,所以 `Bicycle` 中的指定构造器需要带上 `override` 修饰符。
|
子类 `Bicycle` 定义了一个自定义指定构造器 `init()`。这个指定构造器和父类的指定构造器相匹配,所以 `Bicycle` 中的指定构造器需要带上 `override` 修饰符。
|
||||||
|
|
||||||
`Bicycle` 的构造器 `init()` 以调用 `super.init()` 方法开始,这个方法的作用是调用 `Bicycle` 的父类`Vehicle` 的默认构造器。这样可以确保 `Bicycle` 在修改属性之前,它所继承的属性 `numberOfWheels` 能被 `Vehicle` 类初始化。在调用 `super.init()` 之后,属性 `numberOfWheels` 的原值被新值 `2` 替换。
|
`Bicycle` 的构造器 `init()` 以调用 `super.init()` 方法开始,这个方法的作用是调用 `Bicycle` 的父类 `Vehicle` 的默认构造器。这样可以确保 `Bicycle` 在修改属性之前,它所继承的属性 `numberOfWheels` 能被 `Vehicle` 类初始化。在调用 `super.init()` 之后,属性 `numberOfWheels` 的原值被新值 `2` 替换。
|
||||||
|
|
||||||
如果你创建一个 `Bicycle` 实例,你可以调用继承的 `description` 计算型属性去查看属性 `numberOfWheels` 是否有改变:
|
如果你创建一个 `Bicycle` 实例,你可以调用继承的 `description` 计算型属性去查看属性 `numberOfWheels` 是否有改变:
|
||||||
|
|
||||||
@ -607,7 +607,7 @@ print("Bicycle: \(bicycle.description)")
|
|||||||
|
|
||||||
接下来的例子将在实践中展示指定构造器、便利构造器以及构造器的自动继承。这个例子定义了包含三个类 `Food`、`RecipeIngredient` 以及 `ShoppingListItem` 的类层次结构,并将演示它们的构造器是如何相互作用的。
|
接下来的例子将在实践中展示指定构造器、便利构造器以及构造器的自动继承。这个例子定义了包含三个类 `Food`、`RecipeIngredient` 以及 `ShoppingListItem` 的类层次结构,并将演示它们的构造器是如何相互作用的。
|
||||||
|
|
||||||
类层次中的基类是 `Food`,它是一个简单的用来封装食物名字的类。`Food` 类引入了一个叫做 `name` 的 `String` 类型的属性,并且提供了两个构造器来创建`Food`实例:
|
类层次中的基类是 `Food`,它是一个简单的用来封装食物名字的类。`Food` 类引入了一个叫做 `name` 的 `String` 类型的属性,并且提供了两个构造器来创建 `Food` 实例:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Food {
|
class Food {
|
||||||
@ -624,7 +624,7 @@ class Food {
|
|||||||
|
|
||||||
下图中展示了 `Food` 的构造器链:
|
下图中展示了 `Food` 的构造器链:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
类类型没有默认的逐一成员构造器,所以 `Food` 类提供了一个接受单一参数 `name` 的指定构造器。这个构造器可以使用一个特定的名字来创建新的 `Food` 实例:
|
类类型没有默认的逐一成员构造器,所以 `Food` 类提供了一个接受单一参数 `name` 的指定构造器。这个构造器可以使用一个特定的名字来创建新的 `Food` 实例:
|
||||||
|
|
||||||
@ -642,7 +642,7 @@ let mysteryMeat = Food()
|
|||||||
// mysteryMeat 的名字是 [Unnamed]
|
// mysteryMeat 的名字是 [Unnamed]
|
||||||
```
|
```
|
||||||
|
|
||||||
类层级中的第二个类是 `Food` 的子类 `RecipeIngredient`。`RecipeIngredient` 类用来表示食谱中的一项原料。它引入了 `Int` 类型的属性 `quantity`(以及从 `Food` 继承过来的 `name` 属性),并且定义了两个构造器来创建`RecipeIngredient` 实例:
|
类层级中的第二个类是 `Food` 的子类 `RecipeIngredient`。`RecipeIngredient` 类用来表示食谱中的一项原料。它引入了 `Int` 类型的属性 `quantity`(以及从 `Food` 继承过来的 `name` 属性),并且定义了两个构造器来创建 `RecipeIngredient` 实例:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class RecipeIngredient: Food {
|
class RecipeIngredient: Food {
|
||||||
@ -659,19 +659,19 @@ class RecipeIngredient: Food {
|
|||||||
|
|
||||||
下图中展示了 `RecipeIngredient` 类的构造器链:
|
下图中展示了 `RecipeIngredient` 类的构造器链:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
`RecipeIngredient` 类拥有一个指定构造器 `init(name: String, quantity: Int)`,它可以用来填充`RecipeIngredient` 实例的所有属性值。这个构造器一开始先将传入的 `quantity` 参数赋值给 `quantity` 属性,这个属性也是唯一在 `RecipeIngredient` 中新引入的属性。随后,构造器向上代理到父类 `Food` 的`init(name: String)`。这个过程满足[两段式构造过程](#two_phase_initialization)中的安全检查 1。
|
`RecipeIngredient` 类拥有一个指定构造器 `init(name: String, quantity: Int)`,它可以用来填充 `RecipeIngredient` 实例的所有属性值。这个构造器一开始先将传入的 `quantity` 参数赋值给 `quantity` 属性,这个属性也是唯一在 `RecipeIngredient` 中新引入的属性。随后,构造器向上代理到父类 `Food` 的 `init(name: String)`。这个过程满足[两段式构造过程](#two_phase_initialization)中的安全检查 1。
|
||||||
|
|
||||||
`RecipeIngredient` 也定义了一个便利构造器 `init(name: String)`,它只通过 `name` 来创建 `RecipeIngredient` 的实例。这个便利构造器假设任意 `RecipeIngredient` 实例的 `quantity` 为 `1`,所以不需要显式指明数量即可创建出实例。这个便利构造器的定义可以更加方便和快捷地创建实例,并且避免了创建多个`quantity` 为 `1` 的 `RecipeIngredient` 实例时的代码重复。这个便利构造器只是简单地横向代理到类中的指定构造器,并为 `quantity` 参数传递 `1`。
|
`RecipeIngredient` 也定义了一个便利构造器 `init(name: String)`,它只通过 `name` 来创建 `RecipeIngredient` 的实例。这个便利构造器假设任意 `RecipeIngredient` 实例的 `quantity` 为 `1`,所以不需要显式指明数量即可创建出实例。这个便利构造器的定义可以更加方便和快捷地创建实例,并且避免了创建多个 `quantity` 为 `1` 的 `RecipeIngredient` 实例时的代码重复。这个便利构造器只是简单地横向代理到类中的指定构造器,并为 `quantity` 参数传递 `1`。
|
||||||
|
|
||||||
注意,`RecipeIngredient` 的便利构造器 `init(name: String)` 使用了跟 `Food` 中指定构造器 `init(name: String)` 相同的参数。由于这个便利构造器重写了父类的指定构造器 `init(name: String)`,因此必须在前面使用 `override` 修饰符(参见[构造器的继承和重写](#initializer_inheritance_and_overriding))。
|
注意,`RecipeIngredient` 的便利构造器 `init(name: String)` 使用了跟 `Food` 中指定构造器 `init(name: String)` 相同的参数。由于这个便利构造器重写了父类的指定构造器 `init(name: String)`,因此必须在前面使用 `override` 修饰符(参见[构造器的继承和重写](#initializer_inheritance_and_overriding))。
|
||||||
|
|
||||||
尽管 `RecipeIngredient` 将父类的指定构造器重写为了便利构造器,但是它依然提供了父类的所有指定构造器的实现。因此,`RecipeIngredient` 会自动继承父类的所有便利构造器。
|
尽管 `RecipeIngredient` 将父类的指定构造器重写为了便利构造器,但是它依然提供了父类的所有指定构造器的实现。因此,`RecipeIngredient` 会自动继承父类的所有便利构造器。
|
||||||
|
|
||||||
在这个例子中,`RecipeIngredient` 的父类是 `Food`,它有一个便利构造器 `init()`。这个便利构造器会被`RecipeIngredient` 继承。这个继承版本的 `init()` 在功能上跟 `Food` 提供的版本是一样的,只是它会代理到`RecipeIngredient` 版本的 `init(name: String)` 而不是 `Food` 提供的版本。
|
在这个例子中,`RecipeIngredient` 的父类是 `Food`,它有一个便利构造器 `init()`。这个便利构造器会被 `RecipeIngredient` 继承。这个继承版本的 `init()` 在功能上跟 `Food` 提供的版本是一样的,只是它会代理到 `RecipeIngredient` 版本的 `init(name: String)` 而不是 `Food` 提供的版本。
|
||||||
|
|
||||||
所有的这三种构造器都可以用来创建新的 `RecipeIngredient `实例:
|
所有的这三种构造器都可以用来创建新的 `RecipeIngredient` 实例:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let oneMysteryItem = RecipeIngredient()
|
let oneMysteryItem = RecipeIngredient()
|
||||||
@ -739,7 +739,7 @@ for item in breakfastList {
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 严格来说,构造器都不支持返回值。因为构造器本身的作用,只是为了确保对象能被正确构造。因此你只是用`return nil`表明可失败构造器构造失败,而不要用关键字`return`来表明构造成功。
|
> 严格来说,构造器都不支持返回值。因为构造器本身的作用,只是为了确保对象能被正确构造。因此你只是用 `return nil` 表明可失败构造器构造失败,而不要用关键字 `return` 来表明构造成功。
|
||||||
|
|
||||||
例如,实现针对数字类型转换的可失败构造器。确保数字类型之间的转换能保持精确的值,使用这个 `init(exactly:)` 构造器。如果类型转换不能保持值不变,则这个构造器构造失败。
|
例如,实现针对数字类型转换的可失败构造器。确保数字类型之间的转换能保持精确的值,使用这个 `init(exactly:)` 构造器。如果类型转换不能保持值不变,则这个构造器构造失败。
|
||||||
|
|
||||||
@ -761,7 +761,7 @@ if valueChanged == nil {
|
|||||||
// 打印 "3.14159 conversion to Int does not maintain value"
|
// 打印 "3.14159 conversion to Int does not maintain value"
|
||||||
```
|
```
|
||||||
|
|
||||||
下例中,定义了一个名为 `Animal` 的结构体,其中有一个名为 `species` 的 `String` 类型的常量属性。同时该结构体还定义了一个接受一个名为 `species` 的 `String` 类型参数的可失败构造器。这个可失败构造器检查传入的参数是否为一个空字符串。如果为空字符串,则构造失败。否则,`species`属性被赋值,构造成功。
|
下例中,定义了一个名为 `Animal` 的结构体,其中有一个名为 `species` 的 `String` 类型的常量属性。同时该结构体还定义了一个接受一个名为 `species` 的 `String` 类型参数的可失败构造器。这个可失败构造器检查传入的参数是否为一个空字符串。如果为空字符串,则构造失败。否则,`species` 属性被赋值,构造成功。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct Animal {
|
struct Animal {
|
||||||
@ -808,7 +808,7 @@ if anonymousCreature == nil {
|
|||||||
|
|
||||||
你可以通过一个带一个或多个参数的可失败构造器来获取枚举类型中特定的枚举成员。如果提供的参数无法匹配任何枚举成员,则构造失败。
|
你可以通过一个带一个或多个参数的可失败构造器来获取枚举类型中特定的枚举成员。如果提供的参数无法匹配任何枚举成员,则构造失败。
|
||||||
|
|
||||||
下例中,定义了一个名为 `TemperatureUnit` 的枚举类型。其中包含了三个可能的枚举成员(`Kelvin`,`Celsius`,和`Fahrenheit`),以及一个根据 `Character` 值找出所对应的枚举成员的可失败构造器:
|
下例中,定义了一个名为 `TemperatureUnit` 的枚举类型。其中包含了三个可能的枚举成员(`Kelvin`,`Celsius`,和 `Fahrenheit`),以及一个根据 `Character` 值找出所对应的枚举成员的可失败构造器:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
enum TemperatureUnit {
|
enum TemperatureUnit {
|
||||||
@ -880,7 +880,7 @@ if unknownUnit == nil {
|
|||||||
>
|
>
|
||||||
> 可失败构造器也可以代理到其它的非可失败构造器。通过这种方式,你可以增加一个可能的失败状态到现有的构造过程中。
|
> 可失败构造器也可以代理到其它的非可失败构造器。通过这种方式,你可以增加一个可能的失败状态到现有的构造过程中。
|
||||||
|
|
||||||
下面这个例子,定义了一个名为`CartItem`的`Product`类的子类。这个类建立了一个在线购物车中的物品的模型,它有一个名为`quantity`的常量存储型属性,并确保该属性的值至少为`1`:
|
下面这个例子,定义了一个名为 `CartItem` 的 `Product` 类的子类。这个类建立了一个在线购物车中的物品的模型,它有一个名为 `quantity` 的常量存储型属性,并确保该属性的值至少为 `1`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Product {
|
class Product {
|
||||||
@ -960,7 +960,7 @@ class Document {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
下面这个例子,定义了一个 `Document` 类的子类 `AutomaticallyNamedDocument`。这个子类重写了父类的两个指定构造器,确保了无论是使用 `init()` 构造器,还是使用 `init(name:)` 构造器并为参数传递空字符串,生成的实例中的 `name` 属性总有初始`"[Untitled]"`:
|
下面这个例子,定义了一个 `Document` 类的子类 `AutomaticallyNamedDocument`。这个子类重写了父类的两个指定构造器,确保了无论是使用 `init()` 构造器,还是使用 `init(name:)` 构造器并为参数传递空字符串,生成的实例中的 `name` 属性总有初始 `"[Untitled]"`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class AutomaticallyNamedDocument: Document {
|
class AutomaticallyNamedDocument: Document {
|
||||||
@ -996,9 +996,9 @@ class UntitledDocument: Document {
|
|||||||
<a name="the_init!_failable_initializer"></a>
|
<a name="the_init!_failable_initializer"></a>
|
||||||
### init!可失败构造器
|
### init!可失败构造器
|
||||||
|
|
||||||
通常来说我们通过在`init`关键字后添加问号的方式(`init?`)来定义一个可失败构造器,但你也可以通过在`init`后面添加惊叹号的方式来定义一个可失败构造器(`init!`),该可失败构造器将会构建一个对应类型的隐式解包可选类型的对象。
|
通常来说我们通过在 `init` 关键字后添加问号的方式(`init?`)来定义一个可失败构造器,但你也可以通过在 `init` 后面添加惊叹号的方式来定义一个可失败构造器(`init!`),该可失败构造器将会构建一个对应类型的隐式解包可选类型的对象。
|
||||||
|
|
||||||
你可以在 `init?` 中代理到 `init!`,反之亦然。你也可以用 `init?` 重写 `init!`,反之亦然。你还可以用`init` 代理到 `init!`,不过,一旦 `init!` 构造失败,则会触发一个断言。
|
你可以在 `init?` 中代理到 `init!`,反之亦然。你也可以用 `init?` 重写 `init!`,反之亦然。你还可以用 `init` 代理到 `init!`,不过,一旦 `init!` 构造失败,则会触发一个断言。
|
||||||
|
|
||||||
<a name="required_initializers"></a>
|
<a name="required_initializers"></a>
|
||||||
## 必要构造器
|
## 必要构造器
|
||||||
@ -1056,7 +1056,7 @@ class SomeClass {
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
为了呈现这副游戏棋盘,`Chessboard `结构体定义了一个属性 `boardColors`,它是一个包含 `64` 个 `Bool`值的数组。在数组中,值为 `true` 的元素表示一个黑格,值为 `false` 的元素表示一个白格。数组中第一个元素代表棋盘上左上角的格子,最后一个元素代表棋盘上右下角的格子。
|
为了呈现这副游戏棋盘,`Chessboard` 结构体定义了一个属性 `boardColors`,它是一个包含 `64` 个 `Bool` 值的数组。在数组中,值为 `true` 的元素表示一个黑格,值为 `false` 的元素表示一个白格。数组中第一个元素代表棋盘上左上角的格子,最后一个元素代表棋盘上右下角的格子。
|
||||||
|
|
||||||
`boardColors` 数组是通过一个闭包来初始化并设置颜色值的:
|
`boardColors` 数组是通过一个闭包来初始化并设置颜色值的:
|
||||||
|
|
||||||
@ -1080,7 +1080,7 @@ struct Chessboard {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
每当一个新的 `Chessboard` 实例被创建时,赋值闭包则会被执行,`boardColors` 的默认值会被计算出来并返回。上面例子中描述的闭包将计算出棋盘中每个格子对应的颜色,并将这些值保存到一个临时数组 `temporaryBoard` 中,最后在构建完成时将此数组作为闭包返回值返回。这个返回的数组会保存到 `boardColors` 中,并可以通过工具函数`squareIsBlackAtRow`来查询:
|
每当一个新的 `Chessboard` 实例被创建时,赋值闭包则会被执行,`boardColors` 的默认值会被计算出来并返回。上面例子中描述的闭包将计算出棋盘中每个格子对应的颜色,并将这些值保存到一个临时数组 `temporaryBoard` 中,最后在构建完成时将此数组作为闭包返回值返回。这个返回的数组会保存到 `boardColors` 中,并可以通过工具函数 `squareIsBlackAtRow` 来查询:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let board = Chessboard()
|
let board = Chessboard()
|
||||||
|
|||||||
@ -10,9 +10,10 @@
|
|||||||
|
|
||||||
> 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-14
|
> 翻译+校对:[SketchK](https://github.com/SketchK) 2016-05-14
|
||||||
|
|
||||||
> 3.0.1,shanks,2016-11-13
|
> 3.0.1,shanks,2016-11-13
|
||||||
|
|
||||||
> 4.0
|
> 4.0
|
||||||
@ -26,7 +27,7 @@
|
|||||||
- [析构过程原理](#how_deinitialization_works)
|
- [析构过程原理](#how_deinitialization_works)
|
||||||
- [析构器实践](#deinitializers_in_action)
|
- [析构器实践](#deinitializers_in_action)
|
||||||
|
|
||||||
*析构器*只适用于类类型,当一个类的实例被释放之前,析构器会被立即调用。析构器用关键字`deinit`来标示,类似于构造器要用`init`来标示。
|
*析构器*只适用于类类型,当一个类的实例被释放之前,析构器会被立即调用。析构器用关键字 `deinit` 来标示,类似于构造器要用 `init` 来标示。
|
||||||
|
|
||||||
<a name="how_deinitialization_works"></a>
|
<a name="how_deinitialization_works"></a>
|
||||||
## 析构过程原理
|
## 析构过程原理
|
||||||
@ -48,7 +49,7 @@ deinit {
|
|||||||
<a name="deinitializers_in_action"></a>
|
<a name="deinitializers_in_action"></a>
|
||||||
## 析构器实践
|
## 析构器实践
|
||||||
|
|
||||||
这是一个析构器实践的例子。这个例子描述了一个简单的游戏,这里定义了两种新类型,分别是`Bank`和`Player`。`Bank`类管理一种虚拟硬币,确保流通的硬币数量永远不可能超过 10,000。在游戏中有且只能有一个`Bank`存在,因此`Bank`用类来实现,并使用类型属性和类型方法来存储和管理其当前状态。
|
这是一个析构器实践的例子。这个例子描述了一个简单的游戏,这里定义了两种新类型,分别是 `Bank` 和 `Player`。`Bank` 类管理一种虚拟硬币,确保流通的硬币数量永远不可能超过 10,000。在游戏中有且只能有一个 `Bank` 存在,因此 `Bank` 用类来实现,并使用类型属性和类型方法来存储和管理其当前状态。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Bank {
|
class Bank {
|
||||||
@ -64,13 +65,13 @@ class Bank {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`Bank`使用`coinsInBank`属性来跟踪它当前拥有的硬币数量。`Bank`还提供了两个方法,`distribute(coins:)`和`receive(coins:)`,分别用来处理硬币的分发和收集。
|
`Bank` 使用 `coinsInBank` 属性来跟踪它当前拥有的硬币数量。`Bank` 还提供了两个方法,`distribute(coins:)` 和 `receive(coins:)`,分别用来处理硬币的分发和收集。
|
||||||
|
|
||||||
`distribute(coins:)`方法在`Bank`对象分发硬币之前检查是否有足够的硬币。如果硬币不足,`Bank`对象会返回一个比请求时小的数字(如果`Bank`对象中没有硬币了就返回`0`)。此方法返回一个整型值,表示提供的硬币的实际数量。
|
`distribute(coins:)` 方法在 `Bank` 对象分发硬币之前检查是否有足够的硬币。如果硬币不足,`Bank` 对象会返回一个比请求时小的数字(如果 `Bank` 对象中没有硬币了就返回 `0`)。此方法返回一个整型值,表示提供的硬币的实际数量。
|
||||||
|
|
||||||
`receive(coins:)`方法只是将`Bank`实例接收到的硬币数目加回硬币存储中。
|
`receive(coins:)` 方法只是将 `Bank` 实例接收到的硬币数目加回硬币存储中。
|
||||||
|
|
||||||
`Player`类描述了游戏中的一个玩家。每一个玩家在任意时间都有一定数量的硬币存储在他们的钱包中。这通过玩家的`coinsInPurse`属性来表示:
|
`Player` 类描述了游戏中的一个玩家。每一个玩家在任意时间都有一定数量的硬币存储在他们的钱包中。这通过玩家的 `coinsInPurse` 属性来表示:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Player {
|
class Player {
|
||||||
@ -87,9 +88,9 @@ class Player {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
每个`Player`实例在初始化的过程中,都从`Bank`对象获取指定数量的硬币。如果没有足够的硬币可用,`Player`实例可能会收到比指定数量少的硬币。
|
每个 `Player` 实例在初始化的过程中,都从 `Bank` 对象获取指定数量的硬币。如果没有足够的硬币可用,`Player` 实例可能会收到比指定数量少的硬币。
|
||||||
|
|
||||||
`Player`类定义了一个`win(coins:)`方法,该方法从`Bank`对象获取一定数量的硬币,并把它们添加到玩家的钱包。`Player`类还实现了一个析构器,这个析构器在`Player`实例释放前被调用。在这里,析构器的作用只是将玩家的所有硬币都返还给`Bank`对象:
|
`Player` 类定义了一个 `win(coins:)` 方法,该方法从 `Bank` 对象获取一定数量的硬币,并把它们添加到玩家的钱包。`Player` 类还实现了一个析构器,这个析构器在 `Player` 实例释放前被调用。在这里,析构器的作用只是将玩家的所有硬币都返还给 `Bank` 对象:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var playerOne: Player? = Player(coins: 100)
|
var playerOne: Player? = Player(coins: 100)
|
||||||
@ -99,9 +100,9 @@ print("There are now \(Bank.coinsInBank) coins left in the bank")
|
|||||||
// 打印 "There are now 9900 coins left in the bank"
|
// 打印 "There are now 9900 coins left in the bank"
|
||||||
```
|
```
|
||||||
|
|
||||||
创建一个`Player`实例的时候,会向`Bank`对象请求 100 个硬币,如果有足够的硬币可用的话。这个`Player`实例存储在一个名为`playerOne`的可选类型的变量中。这里使用了一个可选类型的变量,因为玩家可以随时离开游戏,设置为可选使你可以追踪玩家当前是否在游戏中。
|
创建一个 `Player` 实例的时候,会向 `Bank` 对象请求 100 个硬币,如果有足够的硬币可用的话。这个 `Player` 实例存储在一个名为 `playerOne` 的可选类型的变量中。这里使用了一个可选类型的变量,因为玩家可以随时离开游戏,设置为可选使你可以追踪玩家当前是否在游戏中。
|
||||||
|
|
||||||
因为`playerOne`是可选的,所以访问其`coinsInPurse`属性来打印钱包中的硬币数量时,使用感叹号(`!`)强制解包:
|
因为 `playerOne` 是可选的,所以访问其 `coinsInPurse` 属性来打印钱包中的硬币数量时,使用感叹号(`!`)强制解包:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
playerOne!.win(coins: 2_000)
|
playerOne!.win(coins: 2_000)
|
||||||
@ -111,7 +112,7 @@ print("The bank now only has \(Bank.coinsInBank) coins left")
|
|||||||
// 输出 "The bank now only has 7900 coins left"
|
// 输出 "The bank now only has 7900 coins left"
|
||||||
```
|
```
|
||||||
|
|
||||||
这里,玩家已经赢得了 2,000 枚硬币,所以玩家的钱包中现在有 2,100 枚硬币,而`Bank`对象只剩余 7,900 枚硬币。
|
这里,玩家已经赢得了 2,000 枚硬币,所以玩家的钱包中现在有 2,100 枚硬币,而 `Bank` 对象只剩余 7,900 枚硬币。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
playerOne = nil
|
playerOne = nil
|
||||||
@ -121,4 +122,4 @@ print("The bank now has \(Bank.coinsInBank) coins")
|
|||||||
// 打印 "The bank now has 10000 coins"
|
// 打印 "The bank now has 10000 coins"
|
||||||
```
|
```
|
||||||
|
|
||||||
玩家现在已经离开了游戏。这通过将可选类型的`playerOne`变量设置为`nil`来表示,意味着“没有`Player`实例”。当这一切发生时,`playerOne`变量对`Player`实例的引用被破坏了。没有其它属性或者变量引用`Player`实例,因此该实例会被释放,以便回收内存。在这之前,该实例的析构器被自动调用,玩家的硬币被返还给银行。
|
玩家现在已经离开了游戏。这通过将可选类型的 `playerOne` 变量设置为 `nil` 来表示,意味着“没有 `Player` 实例”。当这一切发生时,`playerOne` 变量对 `Player` 实例的引用被破坏了。没有其它属性或者变量引用 `Player` 实例,因此该实例会被释放,以便回收内存。在这之前,该实例的析构器被自动调用,玩家的硬币被返还给银行。
|
||||||
|
|||||||
@ -11,9 +11,10 @@
|
|||||||
|
|
||||||
> 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.1,shanks,2016-11-13
|
> 3.0.1,shanks,2016-11-13
|
||||||
|
|
||||||
> 4.0
|
> 4.0
|
||||||
@ -32,24 +33,24 @@
|
|||||||
- [连接多层可选链式调用](#linking_multiple_levels_of_chaining)
|
- [连接多层可选链式调用](#linking_multiple_levels_of_chaining)
|
||||||
- [在方法的可选返回值上进行可选链式调用](#chaining_on_methods_with_optional_return_values)
|
- [在方法的可选返回值上进行可选链式调用](#chaining_on_methods_with_optional_return_values)
|
||||||
|
|
||||||
*可选链式调用*是一种可以在当前值可能为`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>
|
||||||
## 使用可选链式调用代替强制展开
|
## 使用可选链式调用代替强制展开
|
||||||
|
|
||||||
通过在想调用的属性、方法、或下标的可选值后面放一个问号(`?`),可以定义一个可选链。这一点很像在可选值后面放一个叹号(`!`)来强制展开它的值。它们的主要区别在于当可选值为空时可选链式调用只会调用失败,然而强制展开将会触发运行时错误。
|
通过在想调用的属性、方法,或下标的可选值后面放一个问号(`?`),可以定义一个可选链。这一点很像在可选值后面放一个叹号(`!`)来强制展开它的值。它们的主要区别在于当可选值为空时可选链式调用只会调用失败,然而强制展开将会触发运行时错误。
|
||||||
|
|
||||||
为了反映可选链式调用可以在空值(`nil`)上调用的事实,不论这个调用的属性、方法及下标返回的值是不是可选值,它的返回结果都是一个可选值。你可以利用这个返回值来判断你的可选链式调用是否调用成功,如果调用有返回值则说明调用成功,返回`nil`则说明调用失败。
|
为了反映可选链式调用可以在空值(`nil`)上调用的事实,不论这个调用的属性、方法及下标返回的值是不是可选值,它的返回结果都是一个可选值。你可以利用这个返回值来判断你的可选链式调用是否调用成功,如果调用有返回值则说明调用成功,返回 `nil` 则说明调用失败。
|
||||||
|
|
||||||
特别地,可选链式调用的返回结果与原本的返回结果具有相同的类型,但是被包装成了一个可选值。例如,使用可选链式调用访问属性,当可选链式调用成功时,如果属性原本的返回结果是`Int`类型,则会变为`Int?`类型。
|
特别地,可选链式调用的返回结果与原本的返回结果具有相同的类型,但是被包装成了一个可选值。例如,使用可选链式调用访问属性,当可选链式调用成功时,如果属性原本的返回结果是 `Int` 类型,则会变为 `Int?` 类型。
|
||||||
|
|
||||||
下面几段代码将解释可选链式调用和强制展开的不同。
|
下面几段代码将解释可选链式调用和强制展开的不同。
|
||||||
|
|
||||||
首先定义两个类`Person`和`Residence`:
|
首先定义两个类 `Person` 和 `Residence`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Person {
|
class Person {
|
||||||
@ -61,24 +62,24 @@ 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
|
||||||
let john = Person()
|
let john = Person()
|
||||||
```
|
```
|
||||||
|
|
||||||
如果使用叹号(`!`)强制展开获得这个`john`的`residence`属性中的`numberOfRooms`值,会触发运行时错误,因为这时`residence`没有可以展开的值:
|
如果使用叹号(`!`)强制展开获得这个 `john` 的 `residence` 属性中的 `numberOfRooms` 值,会触发运行时错误,因为这时 `residence` 没有可以展开的值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let roomCount = john.residence!.numberOfRooms
|
let roomCount = john.residence!.numberOfRooms
|
||||||
// 这会引发运行时错误
|
// 这会引发运行时错误
|
||||||
```
|
```
|
||||||
|
|
||||||
`john.residence`为非`nil`值的时候,上面的调用会成功,并且把`roomCount`设置为`Int`类型的房间数量。正如上面提到的,当`residence`为`nil`的时候上面这段代码会触发运行时错误。
|
`john.residence` 为非 `nil` 值的时候,上面的调用会成功,并且把 `roomCount` 设置为 `Int` 类型的房间数量。正如上面提到的,当 `residence` 为 `nil` 的时候上面这段代码会触发运行时错误。
|
||||||
|
|
||||||
可选链式调用提供了另一种访问`numberOfRooms`的方式,使用问号(`?`)来替代原来的叹号(`!`):
|
可选链式调用提供了另一种访问 `numberOfRooms` 的方式,使用问号(`?`)来替代原来的叹号(`!`):
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let roomCount = john.residence?.numberOfRooms {
|
if let roomCount = john.residence?.numberOfRooms {
|
||||||
@ -89,19 +90,19 @@ if let roomCount = john.residence?.numberOfRooms {
|
|||||||
// 打印 “Unable to retrieve the number of rooms.”
|
// 打印 “Unable to retrieve the number of rooms.”
|
||||||
```
|
```
|
||||||
|
|
||||||
在`residence`后面添加问号之后,Swift 就会在`residence`不为`nil`的情况下访问`numberOfRooms`。
|
在 `residence` 后面添加问号之后,Swift 就会在 `residence` 不为 `nil` 的情况下访问 `numberOfRooms`。
|
||||||
|
|
||||||
因为访问`numberOfRooms`有可能失败,可选链式调用会返回`Int?`类型,或称为“可选的 `Int`”。如上例所示,当`residence`为`nil`的时候,可选的`Int`将会为`nil`,表明无法访问`numberOfRooms`。访问成功时,可选的`Int`值会通过可选绑定展开,并赋值给非可选类型的`roomCount`常量。
|
因为访问 `numberOfRooms` 有可能失败,可选链式调用会返回 `Int?` 类型,或称为“可选的 `Int`”。如上例所示,当 `residence` 为 `nil` 的时候,可选的 `Int` 将会为 `nil`,表明无法访问 `numberOfRooms`。访问成功时,可选的 `Int` 值会通过可选绑定展开,并赋值给非可选类型的 `roomCount` 常量。
|
||||||
|
|
||||||
要注意的是,即使`numberOfRooms`是非可选的`Int`时,这一点也成立。只要使用可选链式调用就意味着`numberOfRooms`会返回一个`Int?`而不是`Int`。
|
要注意的是,即使 `numberOfRooms` 是非可选的 `Int` 时,这一点也成立。只要使用可选链式调用就意味着 `numberOfRooms` 会返回一个 `Int?` 而不是 `Int`。
|
||||||
|
|
||||||
可以将一个`Residence`的实例赋给`john.residence`,这样它就不再是`nil`了:
|
可以将一个 `Residence` 的实例赋给 `john.residence`,这样它就不再是 `nil` 了:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
john.residence = Residence()
|
john.residence = Residence()
|
||||||
```
|
```
|
||||||
|
|
||||||
`john.residence`现在包含一个实际的`Residence`实例,而不再是`nil`。如果你试图使用先前的可选链式调用访问`numberOfRooms`,它现在将返回值为`1`的`Int?`类型的值:
|
`john.residence` 现在包含一个实际的 `Residence` 实例,而不再是 `nil`。如果你试图使用先前的可选链式调用访问 `numberOfRooms`,它现在将返回值为 `1` 的 `Int?` 类型的值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let roomCount = john.residence?.numberOfRooms {
|
if let roomCount = john.residence?.numberOfRooms {
|
||||||
@ -117,9 +118,9 @@ if let roomCount = john.residence?.numberOfRooms {
|
|||||||
|
|
||||||
通过使用可选链式调用可以调用多层属性、方法和下标。这样可以在复杂的模型中向下访问各种子属性,并且判断能否访问子属性的属性、方法或下标。
|
通过使用可选链式调用可以调用多层属性、方法和下标。这样可以在复杂的模型中向下访问各种子属性,并且判断能否访问子属性的属性、方法或下标。
|
||||||
|
|
||||||
下面这段代码定义了四个模型类,这些例子包括多层可选链式调用。为了方便说明,在`Person`和`Residence`的基础上增加了`Room`类和`Address`类,以及相关的属性、方法以及下标。
|
下面这段代码定义了四个模型类,这些例子包括多层可选链式调用。为了方便说明,在 `Person` 和 `Residence` 的基础上增加了 `Room` 类和 `Address` 类,以及相关的属性、方法以及下标。
|
||||||
|
|
||||||
`Person`类的定义基本保持不变:
|
`Person` 类的定义基本保持不变:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Person {
|
class Person {
|
||||||
@ -127,7 +128,7 @@ class Person {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`Residence`类比之前复杂些,增加了一个名为`rooms`的变量属性,该属性被初始化为`[Room]`类型的空数组:
|
`Residence` 类比之前复杂些,增加了一个名为 `rooms` 的变量属性,该属性被初始化为 `[Room]` 类型的空数组:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Residence {
|
class Residence {
|
||||||
@ -150,15 +151,15 @@ class Residence {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
现在`Residence`有了一个存储`Room`实例的数组,`numberOfRooms`属性被实现为计算型属性,而不是存储型属性。`numberOfRooms`属性简单地返回`rooms`数组的`count`属性的值。
|
现在 `Residence` 有了一个存储 `Room` 实例的数组,`numberOfRooms` 属性被实现为计算型属性,而不是存储型属性。`numberOfRooms` 属性简单地返回 `rooms` 数组的 `count` 属性的值。
|
||||||
|
|
||||||
`Residence`还提供了访问`rooms`数组的快捷方式,即提供可读写的下标来访问`rooms`数组中指定位置的元素。
|
`Residence` 还提供了访问 `rooms` 数组的快捷方式,即提供可读写的下标来访问 `rooms` 数组中指定位置的元素。
|
||||||
|
|
||||||
此外,`Residence`还提供了`printNumberOfRooms`方法,这个方法的作用是打印`numberOfRooms`的值。
|
此外,`Residence` 还提供了 `printNumberOfRooms` 方法,这个方法的作用是打印 `numberOfRooms` 的值。
|
||||||
|
|
||||||
最后,`Residence`还定义了一个可选属性`address`,其类型为`Address?`。`Address`类的定义在下面会说明。
|
最后,`Residence` 还定义了一个可选属性 `address`,其类型为 `Address?`。`Address` 类的定义在下面会说明。
|
||||||
|
|
||||||
`Room`类是一个简单类,其实例被存储在`rooms`数组中。该类只包含一个属性`name`,以及一个用于将该属性设置为适当的房间名的初始化函数:
|
`Room` 类是一个简单类,其实例被存储在 `rooms` 数组中。该类只包含一个属性 `name`,以及一个用于将该属性设置为适当的房间名的初始化函数:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Room {
|
class Room {
|
||||||
@ -167,7 +168,7 @@ class Room {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
最后一个类是`Address`,这个类有三个`String?`类型的可选属性。`buildingName`以及`buildingNumber`属性分别表示某个大厦的名称和号码,第三个属性`street`表示大厦所在街道的名称:
|
最后一个类是 `Address`,这个类有三个 `String?` 类型的可选属性。`buildingName` 以及 `buildingNumber` 属性分别表示某个大厦的名称和号码,第三个属性 `street` 表示大厦所在街道的名称:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Address {
|
class Address {
|
||||||
@ -186,14 +187,14 @@ class Address {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`Address`类提供了`buildingIdentifier()`方法,返回值为`String?`。 如果`buildingName`有值则返回`buildingName`。或者,如果`buildingNumber`和`street`均有值则返回`buildingNumber`。否则,返回`nil`。
|
`Address` 类提供了 `buildingIdentifier()` 方法,返回值为 `String?`。 如果 `buildingName` 有值则返回 `buildingName`。或者,如果 `buildingNumber` 和 `street` 均有值则返回 `buildingNumber`。否则,返回 `nil`。
|
||||||
|
|
||||||
<a name="accessing_properties_through_optional_chaining"></a>
|
<a name="accessing_properties_through_optional_chaining"></a>
|
||||||
## 通过可选链式调用访问属性
|
## 通过可选链式调用访问属性
|
||||||
|
|
||||||
正如[使用可选链式调用代替强制展开](#optional_chaining_as_an_alternative_to_forced_unwrapping)中所述,可以通过可选链式调用在一个可选值上访问它的属性,并判断访问是否成功。
|
正如[使用可选链式调用代替强制展开](#optional_chaining_as_an_alternative_to_forced_unwrapping)中所述,可以通过可选链式调用在一个可选值上访问它的属性,并判断访问是否成功。
|
||||||
|
|
||||||
下面的代码创建了一个`Person`实例,然后像之前一样,尝试访问`numberOfRooms`属性:
|
下面的代码创建了一个 `Person` 实例,然后像之前一样,尝试访问 `numberOfRooms` 属性:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let john = Person()
|
let john = Person()
|
||||||
@ -205,7 +206,7 @@ if let roomCount = john.residence?.numberOfRooms {
|
|||||||
// 打印 “Unable to retrieve the number of rooms.”
|
// 打印 “Unable to retrieve the number of rooms.”
|
||||||
```
|
```
|
||||||
|
|
||||||
因为`john.residence`为`nil`,所以这个可选链式调用依旧会像先前一样失败。
|
因为 `john.residence` 为 `nil`,所以这个可选链式调用依旧会像先前一样失败。
|
||||||
|
|
||||||
还可以通过可选链式调用来设置属性值:
|
还可以通过可选链式调用来设置属性值:
|
||||||
|
|
||||||
@ -216,9 +217,9 @@ someAddress.street = "Acacia Road"
|
|||||||
john.residence?.address = someAddress
|
john.residence?.address = someAddress
|
||||||
```
|
```
|
||||||
|
|
||||||
在这个例子中,通过`john.residence`来设定`address`属性也会失败,因为`john.residence`当前为`nil`。
|
在这个例子中,通过 `john.residence` 来设定 `address` 属性也会失败,因为 `john.residence` 当前为 `nil`。
|
||||||
|
|
||||||
上面代码中的赋值过程是可选链式调用的一部分,这意味着可选链式调用失败时,等号右侧的代码不会被执行。对于上面的代码来说,很难验证这一点,因为像这样赋值一个常量没有任何副作用。下面的代码完成了同样的事情,但是它使用一个函数来创建`Address`实例,然后将该实例返回用于赋值。该函数会在返回前打印“Function was called”,这使你能验证等号右侧的代码是否被执行。
|
上面代码中的赋值过程是可选链式调用的一部分,这意味着可选链式调用失败时,等号右侧的代码不会被执行。对于上面的代码来说,很难验证这一点,因为像这样赋值一个常量没有任何副作用。下面的代码完成了同样的事情,但是它使用一个函数来创建 `Address` 实例,然后将该实例返回用于赋值。该函数会在返回前打印“Function was called”,这使你能验证等号右侧的代码是否被执行。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func createAddress() -> Address {
|
func createAddress() -> Address {
|
||||||
@ -233,14 +234,14 @@ func createAddress() -> Address {
|
|||||||
john.residence?.address = createAddress()
|
john.residence?.address = createAddress()
|
||||||
```
|
```
|
||||||
|
|
||||||
没有任何打印消息,可以看出`createAddress()`函数并未被执行。
|
没有任何打印消息,可以看出 `createAddress()` 函数并未被执行。
|
||||||
|
|
||||||
<a name="calling_methods_through_optional_chaining"></a>
|
<a name="calling_methods_through_optional_chaining"></a>
|
||||||
## 通过可选链式调用调用方法
|
## 通过可选链式调用来调用方法
|
||||||
|
|
||||||
可以通过可选链式调用来调用方法,并判断是否调用成功,即使这个方法没有返回值。
|
可以通过可选链式调用来调用方法,并判断是否调用成功,即使这个方法没有返回值。
|
||||||
|
|
||||||
`Residence`类中的`printNumberOfRooms()`方法打印当前的`numberOfRooms`值,如下所示:
|
`Residence` 类中的 `printNumberOfRooms()` 方法打印当前的 `numberOfRooms` 值,如下所示:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func printNumberOfRooms() {
|
func printNumberOfRooms() {
|
||||||
@ -248,9 +249,9 @@ func printNumberOfRooms() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
这个方法没有返回值。然而,没有返回值的方法具有隐式的返回类型`Void`,如[无返回值函数](./06_Functions.html#functions_without_return_values)中所述。这意味着没有返回值的方法也会返回`()`,或者说空的元组。
|
这个方法没有返回值。然而,没有返回值的方法具有隐式的返回类型 `Void`,如[无返回值函数](./06_Functions.html#functions_without_return_values)中所述。这意味着没有返回值的方法也会返回 `()`,或者说空的元组。
|
||||||
|
|
||||||
如果在可选值上通过可选链式调用来调用这个方法,该方法的返回类型会是`Void?`,而不是`Void`,因为通过可选链式调用得到的返回值都是可选的。这样我们就可以使用`if`语句来判断能否成功调用`printNumberOfRooms()`方法,即使方法本身没有定义返回值。通过判断返回值是否为`nil`可以判断调用是否成功:
|
如果在可选值上通过可选链式调用来调用这个方法,该方法的返回类型会是 `Void?`,而不是 `Void`,因为通过可选链式调用得到的返回值都是可选的。这样我们就可以使用 `if` 语句来判断能否成功调用 `printNumberOfRooms()` 方法,即使方法本身没有定义返回值。通过判断返回值是否为 `nil` 可以判断调用是否成功:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if john.residence?.printNumberOfRooms() != nil {
|
if john.residence?.printNumberOfRooms() != nil {
|
||||||
@ -261,7 +262,7 @@ if john.residence?.printNumberOfRooms() != nil {
|
|||||||
// 打印 “It was not possible to print the number of rooms.”
|
// 打印 “It was not possible to print the number of rooms.”
|
||||||
```
|
```
|
||||||
|
|
||||||
同样的,可以据此判断通过可选链式调用为属性赋值是否成功。在上面的[通过可选链式调用访问属性](#accessing_properties_through_optional_chaining)的例子中,我们尝试给`john.residence`中的`address`属性赋值,即使`residence`为`nil`。通过可选链式调用给属性赋值会返回`Void?`,通过判断返回值是否为`nil`就可以知道赋值是否成功:
|
同样的,可以据此判断通过可选链式调用为属性赋值是否成功。在上面的[通过可选链式调用访问属性](#accessing_properties_through_optional_chaining)的例子中,我们尝试给 `john.residence` 中的 `address` 属性赋值,即使 `residence` 为 `nil`。通过可选链式调用给属性赋值会返回 `Void?`,通过判断返回值是否为 `nil` 就可以知道赋值是否成功:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if (john.residence?.address = someAddress) != nil {
|
if (john.residence?.address = someAddress) != nil {
|
||||||
@ -281,7 +282,7 @@ if (john.residence?.address = someAddress) != nil {
|
|||||||
>
|
>
|
||||||
> 通过可选链式调用访问可选值的下标时,应该将问号放在下标方括号的前面而不是后面。可选链式调用的问号一般直接跟在可选表达式的后面。
|
> 通过可选链式调用访问可选值的下标时,应该将问号放在下标方括号的前面而不是后面。可选链式调用的问号一般直接跟在可选表达式的后面。
|
||||||
|
|
||||||
下面这个例子用下标访问`john.residence`属性存储的`Residence`实例的`rooms`数组中的第一个房间的名称,因为`john.residence`为`nil`,所以下标调用失败了:
|
下面这个例子用下标访问 `john.residence` 属性存储的 `Residence` 实例的 `rooms` 数组中的第一个房间的名称,因为 `john.residence` 为 `nil`,所以下标调用失败了:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let firstRoomName = john.residence?[0].name {
|
if let firstRoomName = john.residence?[0].name {
|
||||||
@ -292,7 +293,7 @@ if let firstRoomName = john.residence?[0].name {
|
|||||||
// 打印 “Unable to retrieve the first room name.”
|
// 打印 “Unable to retrieve the first room name.”
|
||||||
```
|
```
|
||||||
|
|
||||||
在这个例子中,问号直接放在`john.residence`的后面,并且在方括号的前面,因为`john.residence`是可选值。
|
在这个例子中,问号直接放在 `john.residence` 的后面,并且在方括号的前面,因为 `john.residence` 是可选值。
|
||||||
|
|
||||||
类似的,可以通过下标,用可选链式调用来赋值:
|
类似的,可以通过下标,用可选链式调用来赋值:
|
||||||
|
|
||||||
@ -300,9 +301,9 @@ if let firstRoomName = john.residence?[0].name {
|
|||||||
john.residence?[0] = Room(name: "Bathroom")
|
john.residence?[0] = Room(name: "Bathroom")
|
||||||
```
|
```
|
||||||
|
|
||||||
这次赋值同样会失败,因为`residence`目前是`nil`。
|
这次赋值同样会失败,因为 `residence` 目前是 `nil`。
|
||||||
|
|
||||||
如果你创建一个`Residence`实例,并为其`rooms`数组添加一些`Room`实例,然后将`Residence`实例赋值给`john.residence`,那就可以通过可选链和下标来访问数组中的元素:
|
如果你创建一个 `Residence` 实例,并为其 `rooms` 数组添加一些 `Room` 实例,然后将 `Residence` 实例赋值给 `john.residence`,那就可以通过可选链和下标来访问数组中的元素:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let johnsHouse = Residence()
|
let johnsHouse = Residence()
|
||||||
@ -321,7 +322,7 @@ if let firstRoomName = john.residence?[0].name {
|
|||||||
<a name="accessing_subscripts_of_optional_type"></a>
|
<a name="accessing_subscripts_of_optional_type"></a>
|
||||||
### 访问可选类型的下标
|
### 访问可选类型的下标
|
||||||
|
|
||||||
如果下标返回可选类型值,比如 Swift 中`Dictionary`类型的键的下标,可以在下标的结尾括号后面放一个问号来在其可选返回值上进行可选链式调用:
|
如果下标返回可选类型值,比如 Swift 中 `Dictionary` 类型的键的下标,可以在下标的结尾括号后面放一个问号来在其可选返回值上进行可选链式调用:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
|
var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
|
||||||
@ -331,7 +332,7 @@ testScores["Brian"]?[0] = 72
|
|||||||
// "Dave" 数组现在是 [91, 82, 84],"Bev" 数组现在是 [80, 94, 81]
|
// "Dave" 数组现在是 [91, 82, 84],"Bev" 数组现在是 [80, 94, 81]
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的例子中定义了一个`testScores`数组,包含了两个键值对,把`String`类型的键映射到一个`Int`值的数组。这个例子用可选链式调用把`"Dave"`数组中第一个元素设为`91`,把`"Bev"`数组的第一个元素`+1`,然后尝试把`"Brian"`数组中的第一个元素设为`72`。前两个调用成功,因为`testScores`字典中包含`"Dave"`和`"Bev"`这两个键。但是`testScores`字典中没有`"Brian"`这个键,所以第三个调用失败。
|
上面的例子中定义了一个 `testScores` 数组,包含了两个键值对,把 `String` 类型的键映射到一个 `Int` 值的数组。这个例子用可选链式调用把 `"Dave"` 数组中第一个元素设为 `91`,把 `"Bev"` 数组的第一个元素 `+1`,然后尝试把 `"Brian"` 数组中的第一个元素设为 `72`。前两个调用成功,因为 `testScores` 字典中包含 `"Dave"` 和 `"Bev"` 这两个键。但是 `testScores` 字典中没有 `"Brian"` 这个键,所以第三个调用失败。
|
||||||
|
|
||||||
<a name="linking_multiple_levels_of_chaining"></a>
|
<a name="linking_multiple_levels_of_chaining"></a>
|
||||||
## 连接多层可选链式调用
|
## 连接多层可选链式调用
|
||||||
@ -345,10 +346,10 @@ testScores["Brian"]?[0] = 72
|
|||||||
|
|
||||||
因此:
|
因此:
|
||||||
|
|
||||||
+ 通过可选链式调用访问一个`Int`值,将会返回`Int?`,无论使用了多少层可选链式调用。
|
+ 通过可选链式调用访问一个 `Int` 值,将会返回 `Int?`,无论使用了多少层可选链式调用。
|
||||||
+ 类似的,通过可选链式调用访问`Int?`值,依旧会返回`Int?`值,并不会返回`Int??`。
|
+ 类似的,通过可选链式调用访问 `Int?` 值,依旧会返回 `Int?` 值,并不会返回 `Int??`。
|
||||||
|
|
||||||
下面的例子尝试访问`john`中的`residence`属性中的`address`属性中的`street`属性。这里使用了两层可选链式调用,`residence`以及`address`都是可选值:
|
下面的例子尝试访问 `john` 中的 `residence` 属性中的 `address` 属性中的 `street` 属性。这里使用了两层可选链式调用,`residence` 以及 `address` 都是可选值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let johnsStreet = john.residence?.address?.street {
|
if let johnsStreet = john.residence?.address?.street {
|
||||||
@ -359,11 +360,11 @@ if let johnsStreet = john.residence?.address?.street {
|
|||||||
// 打印 “Unable to retrieve the address.”
|
// 打印 “Unable to retrieve the address.”
|
||||||
```
|
```
|
||||||
|
|
||||||
`john.residence`现在包含一个有效的`Residence`实例。然而,`john.residence.address`的值当前为`nil`。因此,调用`john.residence?.address?.street`会失败。
|
`john.residence` 现在包含一个有效的 `Residence` 实例。然而,`john.residence.address` 的值当前为 `nil`。因此,调用 `john.residence?.address?.street` 会失败。
|
||||||
|
|
||||||
需要注意的是,上面的例子中,`street`的属性为`String?`。`john.residence?.address?.street`的返回值也依然是`String?`,即使已经使用了两层可选链式调用。
|
需要注意的是,上面的例子中,`street` 的属性为 `String?`。`john.residence?.address?.street` 的返回值也依然是 `String?`,即使已经使用了两层可选链式调用。
|
||||||
|
|
||||||
如果为`john.residence.address`赋值一个`Address`实例,并且为`address`中的`street`属性设置一个有效值,我们就能过通过可选链式调用来访问`street`属性:
|
如果为 `john.residence.address` 赋值一个 `Address` 实例,并且为 `address` 中的 `street` 属性设置一个有效值,我们就能过通过可选链式调用来访问 `street` 属性:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let johnsAddress = Address()
|
let johnsAddress = Address()
|
||||||
@ -379,14 +380,14 @@ if let johnsStreet = john.residence?.address?.street {
|
|||||||
// 打印 “John's street name is Laurel Street.”
|
// 打印 “John's street name is Laurel Street.”
|
||||||
```
|
```
|
||||||
|
|
||||||
在上面的例子中,因为`john.residence`包含一个有效的`Address`实例,所以对`john.residence`的`address`属性赋值将会成功。
|
在上面的例子中,因为 `john.residence` 包含一个有效的 `Address` 实例,所以对 `john.residence` 的 `address` 属性赋值将会成功。
|
||||||
|
|
||||||
<a name="chaining_on_methods_with_optional_return_values"></a>
|
<a name="chaining_on_methods_with_optional_return_values"></a>
|
||||||
## 在方法的可选返回值上进行可选链式调用
|
## 在方法的可选返回值上进行可选链式调用
|
||||||
|
|
||||||
上面的例子展示了如何在一个可选值上通过可选链式调用来获取它的属性值。我们还可以在一个可选值上通过可选链式调用来调用方法,并且可以根据需要继续在方法的可选返回值上进行可选链式调用。
|
上面的例子展示了如何在一个可选值上通过可选链式调用来获取它的属性值。我们还可以在一个可选值上通过可选链式调用来调用方法,并且可以根据需要继续在方法的可选返回值上进行可选链式调用。
|
||||||
|
|
||||||
在下面的例子中,通过可选链式调用来调用`Address`的`buildingIdentifier()`方法。这个方法返回`String?`类型的值。如上所述,通过可选链式调用来调用该方法,最终的返回值依旧会是`String?`类型:
|
在下面的例子中,通过可选链式调用来调用 `Address` 的 `buildingIdentifier()` 方法。这个方法返回 `String?` 类型的值。如上所述,通过可选链式调用来调用该方法,最终的返回值依旧会是 `String?` 类型:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
|
if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
|
||||||
@ -411,4 +412,4 @@ if let beginsWithThe =
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 在上面的例子中,在方法的圆括号后面加上问号是因为你要在`buildingIdentifier()`方法的可选返回值上进行可选链式调用,而不是`buildingIdentifier()`方法本身。
|
> 在上面的例子中,在方法的圆括号后面加上问号是因为你要在 `buildingIdentifier()` 方法的可选返回值上进行可选链式调用,而不是 `buildingIdentifier()` 方法本身。
|
||||||
|
|||||||
@ -4,12 +4,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.1,shanks,2016-11-13
|
> 3.0.1,shanks,2016-11-13
|
||||||
|
|
||||||
> 4.0
|
> 4.0
|
||||||
@ -32,12 +33,12 @@
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> Swift 中的错误处理涉及到错误处理模式,这会用到 Cocoa 和 Objective-C 中的`NSError`。关于这个类的更多信息请参见 [Using Swift with Cocoa and Objective-C (Swift 4.1)](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.1)](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>
|
||||||
## 表示并抛出错误
|
## 表示并抛出错误
|
||||||
|
|
||||||
在 Swift 中,错误用符合`Error`协议的类型的值来表示。这个空协议表明该类型可以用于错误处理。
|
在 Swift 中,错误用符合 `Error` 协议的类型的值来表示。这个空协议表明该类型可以用于错误处理。
|
||||||
|
|
||||||
Swift 的枚举类型尤为适合构建一组相关的错误状态,枚举的关联值还可以提供错误状态的额外信息。例如,你可以这样表示在一个游戏中操作自动贩卖机时可能会出现的错误状态:
|
Swift 的枚举类型尤为适合构建一组相关的错误状态,枚举的关联值还可以提供错误状态的额外信息。例如,你可以这样表示在一个游戏中操作自动贩卖机时可能会出现的错误状态:
|
||||||
|
|
||||||
@ -49,10 +50,10 @@ enum VendingMachineError: Error {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
抛出一个错误可以让你表明有意外情况发生,导致正常的执行流程无法继续执行。抛出错误使用`throw`关键字。例如,下面的代码抛出一个错误,提示贩卖机还需要`5`个硬币:
|
抛出一个错误可以让你表明有意外情况发生,导致正常的执行流程无法继续执行。抛出错误使用 `throw` 关键字。例如,下面的代码抛出一个错误,提示贩卖机还需要 `5` 个硬币:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
throw VendingMachineError. insufficientFunds(coinsNeeded: 5)
|
throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="handling_errors"></a>
|
<a name="handling_errors"></a>
|
||||||
@ -60,18 +61,18 @@ throw VendingMachineError. insufficientFunds(coinsNeeded: 5)
|
|||||||
|
|
||||||
某个错误被抛出时,附近的某部分代码必须负责处理这个错误,例如纠正这个问题、尝试另外一种方式、或是向用户报告错误。
|
某个错误被抛出时,附近的某部分代码必须负责处理这个错误,例如纠正这个问题、尝试另外一种方式、或是向用户报告错误。
|
||||||
|
|
||||||
Swift 中有`4`种处理错误的方式。你可以把函数抛出的错误传递给调用此函数的代码、用`do-catch`语句处理错误、将错误作为可选类型处理、或者断言此错误根本不会发生。每种方式在下面的小节中都有描述。
|
Swift 中有 `4` 种处理错误的方式。你可以把函数抛出的错误传递给调用此函数的代码、用 `do-catch` 语句处理错误、将错误作为可选类型处理、或者断言此错误根本不会发生。每种方式在下面的小节中都有描述。
|
||||||
|
|
||||||
当一个函数抛出一个错误时,你的程序流程会发生改变,所以重要的是你能迅速识别代码中会抛出错误的地方。为了标识出这些地方,在调用一个能抛出错误的函数、方法或者构造器之前,加上`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>
|
||||||
### 用 throwing 函数传递错误
|
### 用 throwing 函数传递错误
|
||||||
|
|
||||||
为了表示一个函数、方法或构造器可以抛出错误,在函数声明的参数列表之后加上`throws`关键字。一个标有`throws`关键字的函数被称作*throwing 函数*。如果这个函数指明了返回值类型,`throws`关键词需要写在箭头(`->`)的前面。
|
为了表示一个函数、方法或构造器可以抛出错误,在函数声明的参数列表之后加上 `throws` 关键字。一个标有 `throws` 关键字的函数被称作*throwing 函数*。如果这个函数指明了返回值类型,`throws` 关键词需要写在箭头(`->`)的前面。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func canThrowErrors() throws -> String
|
func canThrowErrors() throws -> String
|
||||||
@ -84,7 +85,7 @@ func cannotThrowErrors() -> String
|
|||||||
>
|
>
|
||||||
> 只有 throwing 函数可以传递错误。任何在某个非 throwing 函数内部抛出的错误只能在函数内部处理。
|
> 只有 throwing 函数可以传递错误。任何在某个非 throwing 函数内部抛出的错误只能在函数内部处理。
|
||||||
|
|
||||||
下面的例子中,`VendingMachine`类有一个`vend(itemNamed:)`方法,如果请求的物品不存在、缺货或者投入金额小于物品价格,该方法就会抛出一个相应的`VendingMachineError`:
|
下面的例子中,`VendingMachine` 类有一个 `vend(itemNamed:)` 方法,如果请求的物品不存在、缺货或者投入金额小于物品价格,该方法就会抛出一个相应的 `VendingMachineError`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct Item {
|
struct Item {
|
||||||
@ -127,9 +128,9 @@ class VendingMachine {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
在`vend(itemNamed:)`方法的实现中使用了`guard`语句来提前退出方法,确保在购买某个物品所需的条件中,有任一条件不满足时,能提前退出方法并抛出相应的错误。由于`throw`语句会立即退出方法,所以物品只有在所有条件都满足时才会被售出。
|
在 `vend(itemNamed:)` 方法的实现中使用了 `guard` 语句来提前退出方法,确保在购买某个物品所需的条件中,有任一条件不满足时,能提前退出方法并抛出相应的错误。由于 `throw` 语句会立即退出方法,所以物品只有在所有条件都满足时才会被售出。
|
||||||
|
|
||||||
因为`vend(itemNamed:)`方法会传递出它抛出的任何错误,在你的代码中调用此方法的地方,必须要么直接处理这些错误——使用`do-catch`语句,`try?`或`try!`;要么继续将这些错误传递下去。例如下面例子中,`buyFavoriteSnack(person:vendingMachine:)`同样是一个 throwing 函数,任何由`vend(itemNamed:)`方法抛出的错误会一直被传递到`buyFavoriteSnack(person:vendingMachine:) `函数被调用的地方。
|
因为 `vend(itemNamed:)` 方法会传递出它抛出的任何错误,在你的代码中调用此方法的地方,必须要么直接处理这些错误——使用 `do-catch` 语句,`try?` 或 `try!`;要么继续将这些错误传递下去。例如下面例子中,`buyFavoriteSnack(person:vendingMachine:)` 同样是一个 throwing 函数,任何由 `vend(itemNamed:)` 方法抛出的错误会一直被传递到 `buyFavoriteSnack(person:vendingMachine:)` 函数被调用的地方。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let favoriteSnacks = [
|
let favoriteSnacks = [
|
||||||
@ -143,9 +144,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 {
|
||||||
@ -159,9 +160,9 @@ struct PurchasedSnack {
|
|||||||
|
|
||||||
### 用 Do-Catch 处理错误
|
### 用 Do-Catch 处理错误
|
||||||
|
|
||||||
你可以使用一个`do-catch`语句运行一段闭包代码来处理错误。如果在`do`子句中的代码抛出了一个错误,这个错误会与`catch`子句做匹配,从而决定哪条子句能处理它。
|
你可以使用一个 `do-catch` 语句运行一段闭包代码来处理错误。如果在 `do` 子句中的代码抛出了一个错误,这个错误会与 `catch` 子句做匹配,从而决定哪条子句能处理它。
|
||||||
|
|
||||||
下面是`do-catch`语句的一般形式:
|
下面是 `do-catch` 语句的一般形式:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
do {
|
do {
|
||||||
@ -174,9 +175,9 @@ do {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
在`catch`后面写一个匹配模式来表明这个子句能处理什么样的错误。如果一条`catch`子句没有指定匹配模式,那么这条子句可以匹配任何错误,并且把错误绑定到一个名字为`error`的局部常量。关于模式匹配的更多信息请参考 [模式](../chapter3/07_Patterns.html)。
|
在 `catch` 后面写一个匹配模式来表明这个子句能处理什么样的错误。如果一条 `catch` 子句没有指定匹配模式,那么这条子句可以匹配任何错误,并且把错误绑定到一个名字为 `error` 的局部常量。关于模式匹配的更多信息请参考 [模式](../chapter3/07_Patterns.html)。
|
||||||
|
|
||||||
`catch`子句不必将`do`子句中的代码所抛出的每一个可能的错误都作处理。如果所有`catch`子句都未处理错误,错误就会传递到周围的作用域。然而,错误还是必须要被某个周围的作用域处理的——要么是一个外围的`do-catch`错误处理语句,要么是一个 throwing 函数的内部。举例来说,下面的代码处理了`VendingMachineError`枚举类型的全部枚举值,但是所有其它的错误就必须由它周围的作用域处理:
|
`catch` 子句不必将 `do` 子句中的代码所抛出的每一个可能的错误都作处理。如果所有 `catch` 子句都未处理错误,错误就会传递到周围的作用域。然而,错误还是必须要被某个周围的作用域处理的——要么是一个外围的 `do-catch` 错误处理语句,要么是一个 throwing 函数的内部。举例来说,下面的代码处理了 `VendingMachineError` 枚举类型的全部枚举值,但是所有其它的错误就必须由它周围的作用域处理:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var vendingMachine = VendingMachine()
|
var vendingMachine = VendingMachine()
|
||||||
@ -193,11 +194,11 @@ do {
|
|||||||
// 打印 “Insufficient funds. Please insert an additional 2 coins.”
|
// 打印 “Insufficient funds. Please insert an additional 2 coins.”
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的例子中,`buyFavoriteSnack(person:vendingMachine:) `函数在一个`try`表达式中调用,因为它能抛出错误。如果错误被抛出,相应的执行会马上转移到`catch`子句中,并判断这个错误是否要被继续传递下去。如果没有错误抛出,`do`子句中余下的语句就会被执行。
|
上面的例子中,`buyFavoriteSnack(person:vendingMachine:)` 函数在一个 `try` 表达式中调用,因为它能抛出错误。如果错误被抛出,相应的执行会马上转移到 `catch` 子句中,并判断这个错误是否要被继续传递下去。如果没有错误抛出,`do` 子句中余下的语句就会被执行。
|
||||||
|
|
||||||
### 将错误转换成可选值
|
### 将错误转换成可选值
|
||||||
|
|
||||||
可以使用`try?`通过将错误转换成一个可选值来处理错误。如果在评估`try?`表达式时一个错误被抛出,那么表达式的值就是`nil`。例如,在下面的代码中,`x`和`y`有着相同的数值和等价的含义:
|
可以使用 `try?` 通过将错误转换成一个可选值来处理错误。如果在评估 `try?` 表达式时一个错误被抛出,那么表达式的值就是 `nil`。例如,在下面的代码中,`x` 和 `y` 有着相同的数值和等价的含义:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func someThrowingFunction() throws -> Int {
|
func someThrowingFunction() throws -> Int {
|
||||||
@ -214,9 +215,9 @@ do {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
如果`someThrowingFunction()`抛出一个错误,`x`和`y`的值是`nil`。否则`x`和`y`的值就是该函数的返回值。注意,无论`someThrowingFunction()`的返回值类型是什么类型,`x`和`y`都是这个类型的可选类型。例子中此函数返回一个整型,所以`x`和`y`是可选整型。
|
如果 `someThrowingFunction()` 抛出一个错误,`x` 和 `y` 的值是 `nil`。否则 `x` 和 `y` 的值就是该函数的返回值。注意,无论 `someThrowingFunction()` 的返回值类型是什么类型,`x` 和 `y` 都是这个类型的可选类型。例子中此函数返回一个整型,所以 `x` 和 `y` 是可选整型。
|
||||||
|
|
||||||
如果你想对所有的错误都采用同样的方式来处理,用`try?`就可以让你写出简洁的错误处理代码。例如,下面的代码用几种方式来获取数据,如果所有方式都失败了则返回`nil`。
|
如果你想对所有的错误都采用同样的方式来处理,用 `try?` 就可以让你写出简洁的错误处理代码。例如,下面的代码用几种方式来获取数据,如果所有方式都失败了则返回 `nil`。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func fetchData() -> Data? {
|
func fetchData() -> Data? {
|
||||||
@ -228,9 +229,9 @@ func fetchData() -> Data? {
|
|||||||
|
|
||||||
### 禁用错误传递
|
### 禁用错误传递
|
||||||
|
|
||||||
有时你知道某个`throwing`函数实际上在运行时是不会抛出错误的,在这种情况下,你可以在表达式前面写`try!`来禁用错误传递,这会把调用包装在一个不会有错误抛出的运行时断言中。如果真的抛出了错误,你会得到一个运行时错误。
|
有时你知道某个 `throwing` 函数实际上在运行时是不会抛出错误的,在这种情况下,你可以在表达式前面写 `try!` 来禁用错误传递,这会把调用包装在一个不会有错误抛出的运行时断言中。如果真的抛出了错误,你会得到一个运行时错误。
|
||||||
|
|
||||||
例如,下面的代码使用了`loadImage(atPath:)`函数,该函数从给定的路径加载图片资源,如果图片无法载入则抛出一个错误。在这种情况下,因为图片是和应用绑定的,运行时不会有错误抛出,所以适合禁用错误传递。
|
例如,下面的代码使用了 `loadImage(atPath:)` 函数,该函数从给定的路径加载图片资源,如果图片无法载入则抛出一个错误。在这种情况下,因为图片是和应用绑定的,运行时不会有错误抛出,所以适合禁用错误传递。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
|
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
|
||||||
@ -239,9 +240,9 @@ let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
|
|||||||
<a name="specifying_cleanup_actions"></a>
|
<a name="specifying_cleanup_actions"></a>
|
||||||
## 指定清理操作
|
## 指定清理操作
|
||||||
|
|
||||||
你可以使用`defer`语句在即将离开当前代码块时执行一系列语句。该语句让你能执行一些必要的清理工作,不管是以何种方式离开当前代码块的——无论是由于抛出错误而离开,或是由于诸如`return`、`break`的语句。例如,你可以用`defer`语句来确保文件描述符得以关闭,以及手动分配的内存得以释放。
|
你可以使用 `defer` 语句在即将离开当前代码块时执行一系列语句。该语句让你能执行一些必要的清理工作,不管是以何种方式离开当前代码块的——无论是由于抛出错误而离开,或是由于诸如 `return`、`break` 的语句。例如,你可以用 `defer` 语句来确保文件描述符得以关闭,以及手动分配的内存得以释放。
|
||||||
|
|
||||||
`defer`语句将代码的执行延迟到当前的作用域退出之前。该语句由`defer`关键字和要被延迟执行的语句组成。延迟执行的语句不能包含任何控制转移语句,例如`break`、`return`语句,或是抛出一个错误。延迟执行的操作会按照它们声明的顺序从后往前执行——也就是说,第一条`defer`语句中的代码最后才执行,第二条`defer`语句中的代码倒数第二个执行,以此类推。最后一条语句会第一个执行。
|
`defer` 语句将代码的执行延迟到当前的作用域退出之前。该语句由 `defer` 关键字和要被延迟执行的语句组成。延迟执行的语句不能包含任何控制转移语句,例如 `break`、`return` 语句,或是抛出一个错误。延迟执行的操作会按照它们声明的顺序从后往前执行——也就是说,第一条 `defer` 语句中的代码最后才执行,第二条 `defer` 语句中的代码倒数第二个执行,以此类推。最后一条语句会第一个执行。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func processFile(filename: String) throws {
|
func processFile(filename: String) throws {
|
||||||
@ -258,8 +259,8 @@ func processFile(filename: String) throws {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的代码使用一条`defer`语句来确保`open(_:)`函数有一个相应的对`close(_:)`函数的调用。
|
上面的代码使用一条 `defer` 语句来确保 `open(_:)` 函数有一个相应的对 `close(_:)` 函数的调用。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 即使没有涉及到错误处理的代码,你也可以使用`defer`语句。
|
> 即使没有涉及到错误处理的代码,你也可以使用 `defer` 语句。
|
||||||
|
|||||||
@ -119,7 +119,7 @@ print("Media library contains \(movieCount) movies and \(songCount) songs")
|
|||||||
|
|
||||||
某类型的一个常量或变量可能在幕后实际上属于一个子类。当确定是这种情况时,你可以尝试向下转到它的子类型,用*类型转换操作符*(`as?` 或 `as!`)。
|
某类型的一个常量或变量可能在幕后实际上属于一个子类。当确定是这种情况时,你可以尝试向下转到它的子类型,用*类型转换操作符*(`as?` 或 `as!`)。
|
||||||
|
|
||||||
因为向下转型可能会失败,类型转型操作符带有两种不同形式。条件形式`as?` 返回一个你试图向下转成的类型的可选值。强制形式 `as!` 把试图向下转型和强制解包转换结果结合为一个操作。
|
因为向下转型可能会失败,类型转型操作符带有两种不同形式。条件形式 `as?` 返回一个你试图向下转成的类型的可选值。强制形式 `as!` 把试图向下转型和强制解包转换结果结合为一个操作。
|
||||||
|
|
||||||
当你不确定向下转型可以成功时,用类型转换的条件形式(`as?`)。条件形式的类型转换总是返回一个可选值,并且若下转是不可能的,可选值将是 `nil`。这使你能够检查向下转型是否成功。
|
当你不确定向下转型可以成功时,用类型转换的条件形式(`as?`)。条件形式的类型转换总是返回一个可选值,并且若下转是不可能的,可选值将是 `nil`。这使你能够检查向下转型是否成功。
|
||||||
|
|
||||||
@ -185,7 +185,7 @@ things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
|
|||||||
things.append({ (name: String) -> String in "Hello, \(name)" })
|
things.append({ (name: String) -> String in "Hello, \(name)" })
|
||||||
```
|
```
|
||||||
|
|
||||||
`things` 数组包含两个 `Int` 值,两个 `Double` 值,一个 `String` 值,一个元组 `(Double, Double)`,一个`Movie`实例“Ghostbusters”,以及一个接受 `String` 值并返回另一个 `String` 值的闭包表达式。
|
`things` 数组包含两个 `Int` 值,两个 `Double` 值,一个 `String` 值,一个元组 `(Double, Double)`,一个 `Movie` 实例“Ghostbusters”,以及一个接受 `String` 值并返回另一个 `String` 值的闭包表达式。
|
||||||
|
|
||||||
你可以在 `switch` 表达式的 `case` 中使用 `is` 和 `as` 操作符来找出只知道是 `Any` 或 `AnyObject` 类型的常量或变量的具体类型。下面的示例迭代 `things` 数组中的每一项,并用 `switch` 语句查找每一项的类型。有几个 `switch` 语句的 `case` 绑定它们匹配到的值到一个指定类型的常量,从而可以打印这些值:
|
你可以在 `switch` 表达式的 `case` 中使用 `is` 和 `as` 操作符来找出只知道是 `Any` 或 `AnyObject` 类型的常量或变量的具体类型。下面的示例迭代 `things` 数组中的每一项,并用 `switch` 语句查找每一项的类型。有几个 `switch` 语句的 `case` 绑定它们匹配到的值到一个指定类型的常量,从而可以打印这些值:
|
||||||
|
|
||||||
@ -208,7 +208,7 @@ for thing in things {
|
|||||||
print("an (x, y) point at \(x), \(y)")
|
print("an (x, y) point at \(x), \(y)")
|
||||||
case let movie as Movie:
|
case let movie as Movie:
|
||||||
print("a movie called '\(movie.name)', dir. \(movie.director)")
|
print("a movie called '\(movie.name)', dir. \(movie.director)")
|
||||||
case let stringConverter as String -> String:
|
case let stringConverter as (String) -> String:
|
||||||
print(stringConverter("Michael"))
|
print(stringConverter("Michael"))
|
||||||
default:
|
default:
|
||||||
print("something else")
|
print("something else")
|
||||||
@ -227,7 +227,7 @@ for thing in things {
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> `Any`类型可以表示所有类型的值,包括可选类型。Swift 会在你用`Any`类型来表示一个可选值的时候,给你一个警告。如果你确实想使用`Any`类型来承载可选值,你可以使用`as`操作符显式转换为`Any`,如下所示:
|
> `Any` 类型可以表示所有类型的值,包括可选类型。Swift 会在你用 `Any` 类型来表示一个可选值的时候,给你一个警告。如果你确实想使用 `Any` 类型来承载可选值,你可以使用 `as` 操作符显式转换为 `Any`,如下所示:
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
```swift
|
```swift
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
下面这个例子定义了一个结构体 `BlackjackCard`(二十一点),用来模拟 `BlackjackCard` 中的扑克牌点数。`BlackjackCard` 结构体包含两个嵌套定义的枚举类型 `Suit` 和 `Rank`。
|
下面这个例子定义了一个结构体 `BlackjackCard`(二十一点),用来模拟 `BlackjackCard` 中的扑克牌点数。`BlackjackCard` 结构体包含两个嵌套定义的枚举类型 `Suit` 和 `Rank`。
|
||||||
|
|
||||||
在 `BlackjackCard` 中,`Ace` 牌可以表示 `1` 或者 `11` ,`Ace` 牌的这一特征通过一个嵌套在 `Rank` 枚举中的结构体 `Values` 来表示:
|
在 `BlackjackCard` 中,`Ace` 牌可以表示 `1` 或者 `11`,`Ace` 牌的这一特征通过一个嵌套在 `Rank` 枚举中的结构体 `Values` 来表示:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct BlackjackCard {
|
struct BlackjackCard {
|
||||||
@ -98,7 +98,7 @@ print("theAceOfSpades: \(theAceOfSpades.description)")
|
|||||||
// 打印 “theAceOfSpades: suit is ♠, value is 1 or 11”
|
// 打印 “theAceOfSpades: suit is ♠, value is 1 or 11”
|
||||||
```
|
```
|
||||||
|
|
||||||
尽管 `Rank` 和 `Suit` 嵌套在 `BlackjackCard` 中,但它们的类型仍可从上下文中推断出来,所以在初始化实例时能够单独通过成员名称(`.ace` 和 `.spades`)引用枚举实例。在上面的例子中,`description` 属性正确地反映了黑桃A牌具有 `1` 和 `11` 两个值。
|
尽管 `Rank` 和 `Suit` 嵌套在 `BlackjackCard` 中,但它们的类型仍可从上下文中推断出来,所以在初始化实例时能够单独通过成员名称(`.ace` 和 `.spades`)引用枚举实例。在上面的例子中,`description` 属性正确地反映了黑桃 A 牌具有 `1` 和 `11` 两个值。
|
||||||
|
|
||||||
<a name="referring_to_nested_types"></a>
|
<a name="referring_to_nested_types"></a>
|
||||||
## 引用嵌套类型
|
## 引用嵌套类型
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
> 翻译+校对:[futantan](https://github.com/futantan)
|
> 翻译+校对:[futantan](https://github.com/futantan)
|
||||||
|
|
||||||
> 2.1
|
> 2.1
|
||||||
> 翻译:[小铁匠Linus](https://github.com/kevin833752)
|
> 翻译:[小铁匠 Linus](https://github.com/kevin833752)
|
||||||
> 校对:[shanks](http://codebuild.me)
|
> 校对:[shanks](http://codebuild.me)
|
||||||
>
|
>
|
||||||
> 2.2
|
> 2.2
|
||||||
@ -371,7 +371,7 @@ class SnakesAndLadders: DiceGame {
|
|||||||
var square = 0
|
var square = 0
|
||||||
var board: [Int]
|
var board: [Int]
|
||||||
init() {
|
init() {
|
||||||
board = [Int](count: finalSquare + 1, repeatedValue: 0)
|
board = [Int](repeating: 0, count: finalSquare + 1)
|
||||||
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
|
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
|
||||||
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
|
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
|
||||||
}
|
}
|
||||||
@ -433,7 +433,7 @@ class DiceGameTracker: DiceGameDelegate {
|
|||||||
|
|
||||||
`DiceGameTracker` 实现了 `DiceGameDelegate` 协议要求的三个方法,用来记录游戏已经进行的轮数。当游戏开始时,`numberOfTurns` 属性被赋值为 `0`,然后在每新一轮中递增,游戏结束后,打印游戏的总轮数。
|
`DiceGameTracker` 实现了 `DiceGameDelegate` 协议要求的三个方法,用来记录游戏已经进行的轮数。当游戏开始时,`numberOfTurns` 属性被赋值为 `0`,然后在每新一轮中递增,游戏结束后,打印游戏的总轮数。
|
||||||
|
|
||||||
`gameDidStart(_:)` 方法从 `game` 参数获取游戏信息并打印。`game` 参数是 `DiceGame` 类型而不是 `SnakeAndLadders` 类型,所以在`gameDidStart(_:)` 方法中只能访问 `DiceGame` 协议中的内容。当然了,`SnakeAndLadders` 的方法也可以在类型转换之后调用。在上例代码中,通过 `is` 操作符检查 `game` 是否为 `SnakesAndLadders` 类型的实例,如果是,则打印出相应的消息。
|
`gameDidStart(_:)` 方法从 `game` 参数获取游戏信息并打印。`game` 参数是 `DiceGame` 类型而不是 `SnakeAndLadders` 类型,所以在 `gameDidStart(_:)` 方法中只能访问 `DiceGame` 协议中的内容。当然了,`SnakeAndLadders` 的方法也可以在类型转换之后调用。在上例代码中,通过 `is` 操作符检查 `game` 是否为 `SnakesAndLadders` 类型的实例,如果是,则打印出相应的消息。
|
||||||
|
|
||||||
无论当前进行的是何种游戏,由于 `game` 符合 `DiceGame` 协议,可以确保 `game` 含有 `dice` 属性。因此在 `gameDidStart(_:)` 方法中可以通过传入的 `game` 参数来访问 `dice` 属性,进而打印出 `dice` 的 `sides` 属性的值。
|
无论当前进行的是何种游戏,由于 `game` 符合 `DiceGame` 协议,可以确保 `game` 含有 `dice` 属性。因此在 `gameDidStart(_:)` 方法中可以通过传入的 `game` 参数来访问 `dice` 属性,进而打印出 `dice` 的 `sides` 属性的值。
|
||||||
|
|
||||||
@ -505,9 +505,9 @@ print(game.textualDescription)
|
|||||||
<a name="Conditionally_Conforming_to_a_Protocol"></a>
|
<a name="Conditionally_Conforming_to_a_Protocol"></a>
|
||||||
## 有条件地遵循协议
|
## 有条件地遵循协议
|
||||||
|
|
||||||
泛型类型可能只在某些情况下满足一个协议的要求,比如当类型的泛型形式参数遵循对应协议时。你可以通过在扩展类型时列出限制让泛型类型有条件地遵循某协议。在你采纳协议的名字后面写泛型 `where`分句。更多关于泛型 `where` 分句,见[泛型Where分句](./22_Generics.html##where_clauses)。
|
泛型类型可能只在某些情况下满足一个协议的要求,比如当类型的泛型形式参数遵循对应协议时。你可以通过在扩展类型时列出限制让泛型类型有条件地遵循某协议。在你采纳协议的名字后面写泛型 `where` 分句。更多关于泛型 `where` 分句,见[泛型 Where 分句](./22_Generics.html##where_clauses)。
|
||||||
|
|
||||||
下面的扩展让 `Array` 类型只要在存储遵循 `TextRepresentable`协议的元素时就遵循 `TextRepresentable` 协议。
|
下面的扩展让 `Array` 类型只要在存储遵循 `TextRepresentable` 协议的元素时就遵循 `TextRepresentable` 协议。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
extension Array: TextRepresentable where Element: TextRepresentable {
|
extension Array: TextRepresentable where Element: TextRepresentable {
|
||||||
@ -638,7 +638,7 @@ protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
在以上例子中,协议 `SomeClassOnlyProtocol` 只能被类类型采纳。如果尝试让结构体或枚举类型采纳`SomeClassOnlyProtocol`,则会导致编译时错误。
|
在以上例子中,协议 `SomeClassOnlyProtocol` 只能被类类型采纳。如果尝试让结构体或枚举类型采纳 `SomeClassOnlyProtocol`,则会导致编译时错误。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
@ -678,7 +678,7 @@ wishHappyBirthday(to: birthdayPerson)
|
|||||||
|
|
||||||
上面的例子创建了一个名为 `birthdayPerson` 的 `Person` 的实例,作为参数传递给了 `wishHappyBirthday(to:)` 函数。因为 `Person` 同时符合这两个协议,所以这个参数合法,函数将打印生日问候语。
|
上面的例子创建了一个名为 `birthdayPerson` 的 `Person` 的实例,作为参数传递给了 `wishHappyBirthday(to:)` 函数。因为 `Person` 同时符合这两个协议,所以这个参数合法,函数将打印生日问候语。
|
||||||
|
|
||||||
这里有一个例子:将Location类和前面的Named协议进行组合:
|
这里有一个例子:将 Location 类和前面的 Named 协议进行组合:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Location {
|
class Location {
|
||||||
@ -705,9 +705,9 @@ beginConcert(in: seattle)
|
|||||||
// Prints "Hello, Seattle!"
|
// Prints "Hello, Seattle!"
|
||||||
```
|
```
|
||||||
|
|
||||||
`beginConcert(in:)`方法接受一个类型为 `Location & Named` 的参数,这意味着"任何Location的子类,并且遵循Named协议"。例如,City就满足这样的条件。
|
`beginConcert(in:)` 方法接受一个类型为 `Location & Named` 的参数,这意味着"任何 Location 的子类,并且遵循 Named 协议"。例如,City 就满足这样的条件。
|
||||||
|
|
||||||
将 birthdayPerson 传入`beginConcert(in:)`函数是不合法的,因为 Person不是一个Location的子类。就像,如果你新建一个类继承与Location,但是没有遵循Named协议,你用这个类的实例去调用`beginConcert(in:)`函数也是不合法的。
|
将 birthdayPerson 传入 `beginConcert(in:)` 函数是不合法的,因为 Person 不是一个 Location 的子类。就像,如果你新建一个类继承与 Location,但是没有遵循 Named 协议,你用这个类的实例去调用 `beginConcert(in:)` 函数也是不合法的。
|
||||||
|
|
||||||
<a name="checking_for_protocol_conformance"></a>
|
<a name="checking_for_protocol_conformance"></a>
|
||||||
## 检查协议一致性
|
## 检查协议一致性
|
||||||
@ -786,7 +786,7 @@ for object in objects {
|
|||||||
<a name="optional_protocol_requirements"></a>
|
<a name="optional_protocol_requirements"></a>
|
||||||
## 可选的协议要求
|
## 可选的协议要求
|
||||||
|
|
||||||
协议可以定义*可选要求*,遵循协议的类型可以选择是否实现这些要求。在协议中使用 `optional` 关键字作为前缀来定义可选要求。可选要求用在你需要和 Objective-C 打交道的代码中。协议和可选要求都必须带上`@objc`属性。标记 `@objc` 特性的协议只能被继承自 Objective-C 类的类或者 `@objc` 类遵循,其他类以及结构体和枚举均不能遵循这种协议。
|
协议可以定义*可选要求*,遵循协议的类型可以选择是否实现这些要求。在协议中使用 `optional` 关键字作为前缀来定义可选要求。可选要求用在你需要和 Objective-C 打交道的代码中。协议和可选要求都必须带上 `@objc` 属性。标记 `@objc` 特性的协议只能被继承自 Objective-C 类的类或者 `@objc` 类遵循,其他类以及结构体和枚举均不能遵循这种协议。
|
||||||
|
|
||||||
使用可选要求时(例如,可选的方法或者属性),它们的类型会自动变成可选的。比如,一个类型为 `(Int) -> String` 的方法会变成 `((Int) -> String)?`。需要注意的是整个函数类型是可选的,而不是函数的返回值。
|
使用可选要求时(例如,可选的方法或者属性),它们的类型会自动变成可选的。比如,一个类型为 `(Int) -> String` 的方法会变成 `((Int) -> String)?`。需要注意的是整个函数类型是可选的,而不是函数的返回值。
|
||||||
|
|
||||||
@ -804,6 +804,7 @@ for object in objects {
|
|||||||
`CounterDataSource` 协议定义了一个可选方法 `increment(forCount:)` 和一个可选属性 `fiexdIncrement`,它们使用了不同的方法来从数据源中获取适当的增量值。
|
`CounterDataSource` 协议定义了一个可选方法 `increment(forCount:)` 和一个可选属性 `fiexdIncrement`,它们使用了不同的方法来从数据源中获取适当的增量值。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
|
>
|
||||||
> 严格来讲,`CounterDataSource` 协议中的方法和属性都是可选的,因此遵循协议的类可以不实现这些要求,尽管技术上允许这样做,不过最好不要这样写。
|
> 严格来讲,`CounterDataSource` 协议中的方法和属性都是可选的,因此遵循协议的类可以不实现这些要求,尽管技术上允许这样做,不过最好不要这样写。
|
||||||
|
|
||||||
`Counter` 类含有 `CounterDataSource?` 类型的可选属性 `dataSource`,如下所示:
|
`Counter` 类含有 `CounterDataSource?` 类型的可选属性 `dataSource`,如下所示:
|
||||||
@ -875,7 +876,7 @@ for _ in 1...4 {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`TowardsZeroSource` 实现了 `CounterDataSource` 协议中的 `increment(forCount:) ` 方法,以 `count` 参数为依据,计算出每次的增量。如果 `count` 已经为 `0`,此方法返回 `0`,以此表明之后不应再有增量操作发生。
|
`TowardsZeroSource` 实现了 `CounterDataSource` 协议中的 `increment(forCount:)` 方法,以 `count` 参数为依据,计算出每次的增量。如果 `count` 已经为 `0`,此方法返回 `0`,以此表明之后不应再有增量操作发生。
|
||||||
|
|
||||||
你可以使用 `TowardsZeroSource` 实例将 `Counter` 实例来从 `-4` 增加到 `0`。一旦增加到 `0`,数值便不会再有变动:
|
你可以使用 `TowardsZeroSource` 实例将 `Counter` 实例来从 `-4` 增加到 `0`。一旦增加到 `0`,数值便不会再有变动:
|
||||||
|
|
||||||
@ -940,9 +941,9 @@ extension PrettyTextRepresentable {
|
|||||||
<a name="adding_constraints_to_protocol_extensions"></a>
|
<a name="adding_constraints_to_protocol_extensions"></a>
|
||||||
### 为协议扩展添加限制条件
|
### 为协议扩展添加限制条件
|
||||||
|
|
||||||
在扩展协议的时候,可以指定一些限制条件,只有遵循协议的类型满足这些限制条件时,才能获得协议扩展提供的默认实现。这些限制条件写在协议名之后,使用 `where` 子句来描述,正如[泛型Where子句](./22_Generics.html#where_clauses)中所描述的。
|
在扩展协议的时候,可以指定一些限制条件,只有遵循协议的类型满足这些限制条件时,才能获得协议扩展提供的默认实现。这些限制条件写在协议名之后,使用 `where` 子句来描述,正如[泛型 Where 子句](./22_Generics.html#where_clauses)中所描述的。
|
||||||
|
|
||||||
例如,你可以扩展 `Collection` 协议,适用于集合中的元素遵循了 `Equatable` 协议的情况。通过限制集合元素遵 `Equatable` 协议, 作为标准库的一部分, 你可以使用`==`和`!=`操作符来检查两个元素的等价性和非等价性。
|
例如,你可以扩展 `Collection` 协议,适用于集合中的元素遵循了 `Equatable` 协议的情况。通过限制集合元素遵 `Equatable` 协议, 作为标准库的一部分, 你可以使用 `==` 和 `!=` 操作符来检查两个元素的等价性和非等价性。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
extension Collection where Element: Equatable {
|
extension Collection where Element: Equatable {
|
||||||
@ -966,7 +967,7 @@ extension Collection where Element: Equatable {
|
|||||||
let equalNumbers = [100, 100, 100, 100, 100]
|
let equalNumbers = [100, 100, 100, 100, 100]
|
||||||
let differentNumbers = [100, 100, 200, 100, 200]
|
let differentNumbers = [100, 100, 200, 100, 200]
|
||||||
```
|
```
|
||||||
由于数组遵循`Collection`而且整数遵循`Equatable`, `equalNumbers` 和 `differentNumbers` 都可以使用 `allEqual()` 方法。
|
由于数组遵循 `Collection` 而且整数遵循 `Equatable`,`equalNumbers` 和 `differentNumbers` 都可以使用 `allEqual()` 方法。
|
||||||
|
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
|
|||||||
@ -68,7 +68,7 @@ print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
|
|||||||
// 打印 “someInt is now 107, and anotherInt is now 3”
|
// 打印 “someInt is now 107, and anotherInt is now 3”
|
||||||
```
|
```
|
||||||
|
|
||||||
诚然,`swapTwoInts(_:_:)` 函数挺有用,但是它只能交换 `Int` 值,如果你想要交换两个 `String` 值或者 `Double`值,就不得不写更多的函数,例如 `swapTwoStrings(_:_:)` 和 `swapTwoDoubles(_:_:)`,如下所示:
|
诚然,`swapTwoInts(_:_:)` 函数挺有用,但是它只能交换 `Int` 值,如果你想要交换两个 `String` 值或者 `Double` 值,就不得不写更多的函数,例如 `swapTwoStrings(_:_:)` 和 `swapTwoDoubles(_:_:)`,如下所示:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func swapTwoStrings(_ a: inout String, _ b: inout String) {
|
func swapTwoStrings(_ a: inout String, _ b: inout String) {
|
||||||
@ -354,7 +354,7 @@ func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`findIndex(of:in:)` 唯一的类型参数写做 `T: Equatable`,也就意味着“任何符合 `Equatable` 协议的类型 `T` ”。
|
`findIndex(of:in:)` 唯一的类型参数写做 `T: Equatable`,也就意味着“任何符合 `Equatable` 协议的类型 `T`”。
|
||||||
|
|
||||||
`findIndex(of:in:)` 函数现在可以成功编译了,并且可以作用于任何符合 `Equatable` 的类型,如 `Double` 或 `String`:
|
`findIndex(of:in:)` 函数现在可以成功编译了,并且可以作用于任何符合 `Equatable` 的类型,如 `Double` 或 `String`:
|
||||||
|
|
||||||
@ -373,14 +373,14 @@ let stringIndex = findIndex(of: "Andrea", in: ["Mike", "Malcolm", "Andrea"])
|
|||||||
<a name="associated_types_in_action"></a>
|
<a name="associated_types_in_action"></a>
|
||||||
### 关联类型实践
|
### 关联类型实践
|
||||||
|
|
||||||
下面例子定义了一个 `Container` 协议,该协议定义了一个关联类型 `ItemType`:
|
下面例子定义了一个 `Container` 协议,该协议定义了一个关联类型 `Item`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
protocol Container {
|
protocol Container {
|
||||||
associatedtype ItemType
|
associatedtype Item
|
||||||
mutating func append(_ item: ItemType)
|
mutating func append(_ item: Item)
|
||||||
var count: Int { get }
|
var count: Int { get }
|
||||||
subscript(i: Int) -> ItemType { get }
|
subscript(i: Int) -> Item { get }
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -396,7 +396,7 @@ protocol Container {
|
|||||||
|
|
||||||
为了定义这三个条件,`Container` 协议需要在不知道容器中元素的具体类型的情况下引用这种类型。`Container` 协议需要指定任何通过 `append(_:)` 方法添加到容器中的元素和容器中的元素是相同类型,并且通过容器下标返回的元素的类型也是这种类型。
|
为了定义这三个条件,`Container` 协议需要在不知道容器中元素的具体类型的情况下引用这种类型。`Container` 协议需要指定任何通过 `append(_:)` 方法添加到容器中的元素和容器中的元素是相同类型,并且通过容器下标返回的元素的类型也是这种类型。
|
||||||
|
|
||||||
为了达到这个目的,`Container` 协议声明了一个关联类型 `ItemType`,写作 `associatedtype ItemType`。这个协议无法定义 `ItemType` 是什么类型的别名,这个信息将留给遵从协议的类型来提供。尽管如此,`ItemType` 别名提供了一种方式来引用 `Container` 中元素的类型,并将之用于 `append(_:)` 方法和下标,从而保证任何 `Container` 的行为都能够正如预期地被执行。
|
为了达到这个目的,`Container` 协议声明了一个关联类型 `Item`,写作 `associatedtype Item`。这个协议无法定义 `Item` 是什么类型的别名,这个信息将留给遵从协议的类型来提供。尽管如此,`Item` 别名提供了一种方式来引用 `Container` 中元素的类型,并将之用于 `append(_:)` 方法和下标,从而保证任何 `Container` 的行为都能够正如预期地被执行。
|
||||||
|
|
||||||
下面是先前的非泛型的 `IntStack` 类型,这一版本采纳并符合了 `Container` 协议:
|
下面是先前的非泛型的 `IntStack` 类型,这一版本采纳并符合了 `Container` 协议:
|
||||||
|
|
||||||
@ -411,7 +411,7 @@ struct IntStack: Container {
|
|||||||
return items.removeLast()
|
return items.removeLast()
|
||||||
}
|
}
|
||||||
// Container 协议的实现部分
|
// Container 协议的实现部分
|
||||||
typealias ItemType = Int
|
typealias Item = Int
|
||||||
mutating func append(_ item: Int) {
|
mutating func append(_ item: Int) {
|
||||||
self.push(item)
|
self.push(item)
|
||||||
}
|
}
|
||||||
@ -426,9 +426,9 @@ struct IntStack: Container {
|
|||||||
|
|
||||||
`IntStack` 结构体实现了 `Container` 协议的三个要求,其原有功能也不会和这些要求相冲突。
|
`IntStack` 结构体实现了 `Container` 协议的三个要求,其原有功能也不会和这些要求相冲突。
|
||||||
|
|
||||||
此外,`IntStack` 在实现 `Container` 的要求时,指定 `ItemType` 为 `Int` 类型,即 `typealias ItemType = Int`,从而将 `Container` 协议中抽象的 `ItemType` 类型转换为具体的 `Int` 类型。
|
此外,`IntStack` 在实现 `Container` 的要求时,指定 `Item` 为 `Int` 类型,即 `typealias Item = Int`,从而将 `Container` 协议中抽象的 `Item` 类型转换为具体的 `Int` 类型。
|
||||||
|
|
||||||
由于 Swift 的类型推断,你实际上不用在 `IntStack` 的定义中声明 `ItemType` 为 `Int`。因为 `IntStack` 符合 `Container` 协议的所有要求,Swift 只需通过 `append(_:)` 方法的 `item` 参数类型和下标返回值的类型,就可以推断出 `ItemType` 的具体类型。事实上,如果你在上面的代码中删除了 `typealias ItemType = Int` 这一行,一切仍旧可以正常工作,因为 Swift 清楚地知道 `ItemType` 应该是哪种类型。
|
由于 Swift 的类型推断,你实际上不用在 `IntStack` 的定义中声明 `Item` 为 `Int`。因为 `IntStack` 符合 `Container` 协议的所有要求,Swift 只需通过 `append(_:)` 方法的 `item` 参数类型和下标返回值的类型,就可以推断出 `Item` 的具体类型。事实上,如果你在上面的代码中删除了 `typealias Item = Int` 这一行,一切仍旧可以正常工作,因为 Swift 清楚地知道 `Item` 应该是哪种类型。
|
||||||
|
|
||||||
你也可以让泛型 `Stack` 结构体遵从 `Container` 协议:
|
你也可以让泛型 `Stack` 结构体遵从 `Container` 协议:
|
||||||
|
|
||||||
@ -455,7 +455,7 @@ struct Stack<Element>: Container {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
这一次,占位类型参数 `Element` 被用作 `append(_:)` 方法的 `item` 参数和下标的返回类型。Swift 可以据此推断出 `Element` 的类型即是 `ItemType` 的类型。
|
这一次,占位类型参数 `Element` 被用作 `append(_:)` 方法的 `item` 参数和下标的返回类型。Swift 可以据此推断出 `Element` 的类型即是 `Item` 的类型。
|
||||||
|
|
||||||
<a name="extending_an_existing_type_to_specify_an_associated_type"></a>
|
<a name="extending_an_existing_type_to_specify_an_associated_type"></a>
|
||||||
### 通过扩展一个存在的类型来指定关联类型
|
### 通过扩展一个存在的类型来指定关联类型
|
||||||
@ -468,7 +468,7 @@ Swift 的 `Array` 类型已经提供 `append(_:)` 方法,一个 `count` 属性
|
|||||||
extension Array: Container {}
|
extension Array: Container {}
|
||||||
```
|
```
|
||||||
|
|
||||||
如同上面的泛型 `Stack` 结构体一样,`Array` 的 `append(_:)` 方法和下标确保了 Swift 可以推断出 `ItemType` 的类型。定义了这个扩展后,你可以将任意 `Array` 当作 `Container` 来使用。
|
如同上面的泛型 `Stack` 结构体一样,`Array` 的 `append(_:)` 方法和下标确保了 Swift 可以推断出 `Item` 的类型。定义了这个扩展后,你可以将任意 `Array` 当作 `Container` 来使用。
|
||||||
|
|
||||||
<a name="using_type_annotations_to_constrain_an_associated_type"></a>
|
<a name="using_type_annotations_to_constrain_an_associated_type"></a>
|
||||||
### 给关联类型添加约束
|
### 给关联类型添加约束
|
||||||
@ -489,7 +489,7 @@ protocol Container {
|
|||||||
<a name="Using_a_Protocol_in_Its_Associated_Type’s_Constraints"></a>
|
<a name="Using_a_Protocol_in_Its_Associated_Type’s_Constraints"></a>
|
||||||
### 在关联类型约束里使用协议
|
### 在关联类型约束里使用协议
|
||||||
|
|
||||||
协议可以作为它自身的要求出现。例如,有一个协议细化了 `Container` 协议,添加了一个 `suffix(_:)` 方法。 `suffix(_:)` 方法返回容器中从后往前给定数量的元素,把它们存储在一个 `Suffix` 类型的实例里。
|
协议可以作为它自身的要求出现。例如,有一个协议细化了 `Container` 协议,添加了一个 `suffix(_:)` 方法。`suffix(_:)` 方法返回容器中从后往前给定数量的元素,把它们存储在一个 `Suffix` 类型的实例里。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
protocol SuffixableContainer: Container {
|
protocol SuffixableContainer: Container {
|
||||||
@ -498,7 +498,7 @@ protocol SuffixableContainer: Container {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
在这个协议里, `Suffix` 是一个关联类型,就像上边例子中 `Container` 的 `Item` 类型一样。 `Suffix` 拥有两个约束:它必须遵循 `SuffixableContainer` 协议(就是当前定义的协议),以及它的 `Item` 类型必须是和容器里的 `Item` 类型相同。 `Item` 的约束是一个 `wher`e 分句,它在下面[带有泛型 Where 分句的扩展](#extensions_with_a_generic_where_clause)中有讨论。
|
在这个协议里,`Suffix` 是一个关联类型,就像上边例子中 `Container` 的 `Item` 类型一样。`Suffix` 拥有两个约束:它必须遵循 `SuffixableContainer` 协议(就是当前定义的协议),以及它的 `Item` 类型必须是和容器里的 `Item` 类型相同。`Item` 的约束是一个 `wher`e 分句,它在下面[带有泛型 Where 分句的扩展](#extensions_with_a_generic_where_clause)中有讨论。
|
||||||
|
|
||||||
这里有一个来自[闭包的循环强引用](./23_Automatic_Reference_Counting.html#strong_reference_cycles_for_closures)的 Stack 类型的扩展,它添加了对 `SuffixableContainer` 协议的遵循:
|
这里有一个来自[闭包的循环强引用](./23_Automatic_Reference_Counting.html#strong_reference_cycles_for_closures)的 Stack 类型的扩展,它添加了对 `SuffixableContainer` 协议的遵循:
|
||||||
|
|
||||||
@ -521,7 +521,7 @@ let suffix = stackOfInts.suffix(2)
|
|||||||
// suffix contains 20 and 30
|
// suffix contains 20 and 30
|
||||||
```
|
```
|
||||||
|
|
||||||
在上面的例子中, `Suffix` 是 `Stack` 的关联类型,也就是 `Stack` ,所以 `Stack` 的后缀运算返回另一个 `Stack` 。另外,遵循 `SuffixableContainer` 的类型可以拥有一个与它自己不同的 `Suffix` 类型——也就是说后缀运算可以返回不同的类型。比如说,这里有一个非泛型 `IntStack` 类型的扩展,它添加了 `SuffixableContainer` 遵循,使用 `Stack<Int>` 作为它的后缀类型而不是 `IntStack` :
|
在上面的例子中,`Suffix` 是 `Stack` 的关联类型,也就是 `Stack` ,所以 `Stack` 的后缀运算返回另一个 `Stack` 。另外,遵循 `SuffixableContainer` 的类型可以拥有一个与它自己不同的 `Suffix` 类型——也就是说后缀运算可以返回不同的类型。比如说,这里有一个非泛型 `IntStack` 类型的扩展,它添加了 `SuffixableContainer` 遵循,使用 `Stack<Int>` 作为它的后缀类型而不是 `IntStack`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
extension IntStack: SuffixableContainer {
|
extension IntStack: SuffixableContainer {
|
||||||
@ -551,7 +551,7 @@ extension IntStack: SuffixableContainer {
|
|||||||
```swift
|
```swift
|
||||||
func allItemsMatch<C1: Container, C2: Container>
|
func allItemsMatch<C1: Container, C2: Container>
|
||||||
(_ someContainer: C1, _ anotherContainer: C2) -> Bool
|
(_ someContainer: C1, _ anotherContainer: C2) -> Bool
|
||||||
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
|
where C1.Item == C2.Item, C1.Item: Equatable {
|
||||||
|
|
||||||
// 检查两个容器含有相同数量的元素
|
// 检查两个容器含有相同数量的元素
|
||||||
if someContainer.count != anotherContainer.count {
|
if someContainer.count != anotherContainer.count {
|
||||||
@ -576,8 +576,8 @@ func allItemsMatch<C1: Container, C2: Container>
|
|||||||
|
|
||||||
- `C1` 必须符合 `Container` 协议(写作 `C1: Container`)。
|
- `C1` 必须符合 `Container` 协议(写作 `C1: Container`)。
|
||||||
- `C2` 必须符合 `Container` 协议(写作 `C2: Container`)。
|
- `C2` 必须符合 `Container` 协议(写作 `C2: Container`)。
|
||||||
- `C1` 的 `ItemType` 必须和 `C2` 的 `ItemType`类型相同(写作 `C1.ItemType == C2.ItemType`)。
|
- `C1` 的 `Item` 必须和 `C2` 的 `Item` 类型相同(写作 `C1.Item == C2.Item`)。
|
||||||
- `C1` 的 `ItemType` 必须符合 `Equatable` 协议(写作 `C1.ItemType: Equatable`)。
|
- `C1` 的 `Item` 必须符合 `Equatable` 协议(写作 `C1.Item: Equatable`)。
|
||||||
|
|
||||||
第三个和第四个要求被定义为一个 `where` 子句,写在关键字 `where` 后面,它们也是泛型函数类型参数列表的一部分。
|
第三个和第四个要求被定义为一个 `where` 子句,写在关键字 `where` 后面,它们也是泛型函数类型参数列表的一部分。
|
||||||
|
|
||||||
|
|||||||
@ -47,14 +47,14 @@ Swift 使用*自动引用计数(ARC)*机制来跟踪和管理你的应用程
|
|||||||
|
|
||||||
然而,当 ARC 收回和释放了正在被使用中的实例,该实例的属性和方法将不能再被访问和调用。实际上,如果你试图访问这个实例,你的应用程序很可能会崩溃。
|
然而,当 ARC 收回和释放了正在被使用中的实例,该实例的属性和方法将不能再被访问和调用。实际上,如果你试图访问这个实例,你的应用程序很可能会崩溃。
|
||||||
|
|
||||||
为了确保使用中的实例不会被销毁,ARC 会跟踪和计算每一个实例正在被多少属性,常量和变量所引用。哪怕实例的引用数为1,ARC都不会销毁这个实例。
|
为了确保使用中的实例不会被销毁,ARC 会跟踪和计算每一个实例正在被多少属性,常量和变量所引用。哪怕实例的引用数为1,ARC 都不会销毁这个实例。
|
||||||
|
|
||||||
为了使上述成为可能,无论你将实例赋值给属性、常量或变量,它们都会创建此实例的强引用。之所以称之为“强”引用,是因为它会将实例牢牢地保持住,只要强引用还在,实例是不允许被销毁的。
|
为了使上述成为可能,无论你将实例赋值给属性、常量或变量,它们都会创建此实例的强引用。之所以称之为“强”引用,是因为它会将实例牢牢地保持住,只要强引用还在,实例是不允许被销毁的。
|
||||||
|
|
||||||
<a name="arc_in_action"></a>
|
<a name="arc_in_action"></a>
|
||||||
## 自动引用计数实践
|
## 自动引用计数实践
|
||||||
|
|
||||||
下面的例子展示了自动引用计数的工作机制。例子以一个简单的`Person`类开始,并定义了一个叫`name`的常量属性:
|
下面的例子展示了自动引用计数的工作机制。例子以一个简单的 `Person` 类开始,并定义了一个叫 `name` 的常量属性:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Person {
|
class Person {
|
||||||
@ -69,9 +69,9 @@ class Person {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`Person`类有一个构造函数,此构造函数为实例的`name`属性赋值,并打印一条消息以表明初始化过程生效。`Person`类也拥有一个析构函数,这个析构函数会在实例被销毁时打印一条消息。
|
`Person` 类有一个构造函数,此构造函数为实例的 `name` 属性赋值,并打印一条消息以表明初始化过程生效。`Person` 类也拥有一个析构函数,这个析构函数会在实例被销毁时打印一条消息。
|
||||||
|
|
||||||
接下来的代码片段定义了三个类型为`Person?`的变量,用来按照代码片段中的顺序,为新的`Person`实例建立多个引用。由于这些变量是被定义为可选类型(`Person?`,而不是`Person`),它们的值会被自动初始化为`nil`,目前还不会引用到`Person`类的实例。
|
接下来的代码片段定义了三个类型为 `Person?` 的变量,用来按照代码片段中的顺序,为新的 `Person` 实例建立多个引用。由于这些变量是被定义为可选类型(`Person?`,而不是 `Person`),它们的值会被自动初始化为 `nil`,目前还不会引用到 `Person` 类的实例。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var reference1: Person?
|
var reference1: Person?
|
||||||
@ -79,34 +79,34 @@ var reference2: Person?
|
|||||||
var reference3: Person?
|
var reference3: Person?
|
||||||
```
|
```
|
||||||
|
|
||||||
现在你可以创建`Person`类的新实例,并且将它赋值给三个变量中的一个:
|
现在你可以创建 `Person` 类的新实例,并且将它赋值给三个变量中的一个:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
reference1 = Person(name: "John Appleseed")
|
reference1 = Person(name: "John Appleseed")
|
||||||
// 打印 "John Appleseed is being initialized"
|
// 打印 "John Appleseed is being initialized"
|
||||||
```
|
```
|
||||||
|
|
||||||
应当注意到当你调用`Person`类的构造函数的时候,`"John Appleseed is being initialized"`会被打印出来。由此可以确定构造函数被执行。
|
应当注意到当你调用 `Person` 类的构造函数的时候,`"John Appleseed is being initialized"` 会被打印出来。由此可以确定构造函数被执行。
|
||||||
|
|
||||||
由于`Person`类的新实例被赋值给了`reference1`变量,所以`reference1`到`Person`类的新实例之间建立了一个强引用。正是因为这一个强引用,ARC 会保证`Person`实例被保持在内存中不被销毁。
|
由于 `Person` 类的新实例被赋值给了 `reference1` 变量,所以 `reference1` 到 `Person` 类的新实例之间建立了一个强引用。正是因为这一个强引用,ARC 会保证 `Person` 实例被保持在内存中不被销毁。
|
||||||
|
|
||||||
如果你将同一个`Person`实例也赋值给其他两个变量,该实例又会多出两个强引用:
|
如果你将同一个 `Person` 实例也赋值给其他两个变量,该实例又会多出两个强引用:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
reference2 = reference1
|
reference2 = reference1
|
||||||
reference3 = reference1
|
reference3 = reference1
|
||||||
```
|
```
|
||||||
|
|
||||||
现在这一个`Person`实例已经有三个强引用了。
|
现在这一个 `Person` 实例已经有三个强引用了。
|
||||||
|
|
||||||
如果你通过给其中两个变量赋值`nil`的方式断开两个强引用(包括最先的那个强引用),只留下一个强引用,`Person`实例不会被销毁:
|
如果你通过给其中两个变量赋值 `nil` 的方式断开两个强引用(包括最先的那个强引用),只留下一个强引用,`Person` 实例不会被销毁:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
reference1 = nil
|
reference1 = nil
|
||||||
reference2 = nil
|
reference2 = nil
|
||||||
```
|
```
|
||||||
|
|
||||||
在你清楚地表明不再使用这个`Person`实例时,即第三个也就是最后一个强引用被断开时,ARC 会销毁它:
|
在你清楚地表明不再使用这个 `Person` 实例时,即第三个也就是最后一个强引用被断开时,ARC 会销毁它:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
reference3 = nil
|
reference3 = nil
|
||||||
@ -116,13 +116,13 @@ reference3 = nil
|
|||||||
<a name="strong_reference_cycles_between_class_instances"></a>
|
<a name="strong_reference_cycles_between_class_instances"></a>
|
||||||
## 类实例之间的循环强引用
|
## 类实例之间的循环强引用
|
||||||
|
|
||||||
在上面的例子中,ARC 会跟踪你所新创建的`Person`实例的引用数量,并且会在`Person`实例不再被需要时销毁它。
|
在上面的例子中,ARC 会跟踪你所新创建的 `Person` 实例的引用数量,并且会在 `Person` 实例不再被需要时销毁它。
|
||||||
|
|
||||||
然而,我们可能会写出一个类实例的强引用数*永远不能*变成`0`的代码。如果两个类实例互相持有对方的强引用,因而每个实例都让对方一直存在,就是这种情况。这就是所谓的*循环强引用*。
|
然而,我们可能会写出一个类实例的强引用数*永远不能*变成 `0` 的代码。如果两个类实例互相持有对方的强引用,因而每个实例都让对方一直存在,就是这种情况。这就是所谓的*循环强引用*。
|
||||||
|
|
||||||
你可以通过定义类之间的关系为弱引用或无主引用,以替代强引用,从而解决循环强引用的问题。具体的过程在[解决类实例之间的循环强引用](#resolving_strong_reference_cycles_between_class_instances)中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是怎样产生的。
|
你可以通过定义类之间的关系为弱引用或无主引用,以替代强引用,从而解决循环强引用的问题。具体的过程在[解决类实例之间的循环强引用](#resolving_strong_reference_cycles_between_class_instances)中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是怎样产生的。
|
||||||
|
|
||||||
下面展示了一个不经意产生循环强引用的例子。例子定义了两个类:`Person`和`Apartment`,用来建模公寓和它其中的居民:
|
下面展示了一个不经意产生循环强引用的例子。例子定义了两个类:`Person` 和 `Apartment`,用来建模公寓和它其中的居民:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Person {
|
class Person {
|
||||||
@ -140,31 +140,31 @@ class Apartment {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
每一个`Person`实例有一个类型为`String`,名字为`name`的属性,并有一个可选的初始化为`nil`的`apartment`属性。`apartment`属性是可选的,因为一个人并不总是拥有公寓。
|
每一个 `Person` 实例有一个类型为 `String`,名字为 `name` 的属性,并有一个可选的初始化为 `nil` 的 `apartment` 属性。`apartment` 属性是可选的,因为一个人并不总是拥有公寓。
|
||||||
|
|
||||||
类似的,每个`Apartment`实例有一个叫`unit`,类型为`String`的属性,并有一个可选的初始化为`nil`的`tenant`属性。`tenant`属性是可选的,因为一栋公寓并不总是有居民。
|
类似的,每个 `Apartment` 实例有一个叫 `unit`,类型为 `String` 的属性,并有一个可选的初始化为 `nil` 的 `tenant` 属性。`tenant` 属性是可选的,因为一栋公寓并不总是有居民。
|
||||||
|
|
||||||
这两个类都定义了析构函数,用以在类实例被析构的时候输出信息。这让你能够知晓`Person`和`Apartment`的实例是否像预期的那样被销毁。
|
这两个类都定义了析构函数,用以在类实例被析构的时候输出信息。这让你能够知晓 `Person` 和 `Apartment` 的实例是否像预期的那样被销毁。
|
||||||
|
|
||||||
接下来的代码片段定义了两个可选类型的变量`john`和`unit4A`,并分别被设定为下面的`Apartment`和`Person`的实例。这两个变量都被初始化为`nil`,这正是可选类型的优点:
|
接下来的代码片段定义了两个可选类型的变量 `john` 和 `unit4A`,并分别被设定为下面的 `Apartment` 和 `Person` 的实例。这两个变量都被初始化为 `nil`,这正是可选类型的优点:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var john: Person?
|
var john: Person?
|
||||||
var unit4A: Apartment?
|
var unit4A: Apartment?
|
||||||
```
|
```
|
||||||
|
|
||||||
现在你可以创建特定的`Person`和`Apartment`实例并将赋值给`john`和`unit4A`变量:
|
现在你可以创建特定的 `Person` 和 `Apartment` 实例并将赋值给 `john` 和 `unit4A` 变量:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
john = Person(name: "John Appleseed")
|
john = Person(name: "John Appleseed")
|
||||||
unit4A = Apartment(unit: "4A")
|
unit4A = Apartment(unit: "4A")
|
||||||
```
|
```
|
||||||
|
|
||||||
在两个实例被创建和赋值后,下图表现了强引用的关系。变量`john`现在有一个指向`Person`实例的强引用,而变量`unit4A`有一个指向`Apartment`实例的强引用:
|
在两个实例被创建和赋值后,下图表现了强引用的关系。变量 `john` 现在有一个指向 `Person` 实例的强引用,而变量 `unit4A` 有一个指向 `Apartment` 实例的强引用:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
现在你能够将这两个实例关联在一起,这样人就能有公寓住了,而公寓也有了房客。注意感叹号是用来展开和访问可选变量`john`和`unit4A`中的实例,这样实例的属性才能被赋值:
|
现在你能够将这两个实例关联在一起,这样人就能有公寓住了,而公寓也有了房客。注意感叹号是用来展开和访问可选变量 `john` 和 `unit4A` 中的实例,这样实例的属性才能被赋值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
john!.apartment = unit4A
|
john!.apartment = unit4A
|
||||||
@ -175,20 +175,20 @@ unit4A!.tenant = john
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
不幸的是,这两个实例关联后会产生一个循环强引用。`Person`实例现在有了一个指向`Apartment`实例的强引用,而`Apartment`实例也有了一个指向`Person`实例的强引用。因此,当你断开`john`和`unit4A`变量所持有的强引用时,引用计数并不会降为`0`,实例也不会被 ARC 销毁:
|
不幸的是,这两个实例关联后会产生一个循环强引用。`Person` 实例现在有了一个指向 `Apartment` 实例的强引用,而 `Apartment` 实例也有了一个指向 `Person` 实例的强引用。因此,当你断开 `john` 和 `unit4A` 变量所持有的强引用时,引用计数并不会降为 `0`,实例也不会被 ARC 销毁:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
john = nil
|
john = nil
|
||||||
unit4A = nil
|
unit4A = nil
|
||||||
```
|
```
|
||||||
|
|
||||||
注意,当你把这两个变量设为`nil`时,没有任何一个析构函数被调用。循环强引用会一直阻止`Person`和`Apartment`类实例的销毁,这就在你的应用程序中造成了内存泄漏。
|
注意,当你把这两个变量设为 `nil` 时,没有任何一个析构函数被调用。循环强引用会一直阻止 `Person` 和 `Apartment` 类实例的销毁,这就在你的应用程序中造成了内存泄漏。
|
||||||
|
|
||||||
在你将`john`和`unit4A`赋值为`nil`后,强引用关系如下图:
|
在你将 `john` 和 `unit4A` 赋值为 `nil` 后,强引用关系如下图:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
`Person`和`Apartment`实例之间的强引用关系保留了下来并且不会被断开。
|
`Person` 和 `Apartment` 实例之间的强引用关系保留了下来并且不会被断开。
|
||||||
|
|
||||||
<a name="resolving_strong_reference_cycles_between_class_instances"></a>
|
<a name="resolving_strong_reference_cycles_between_class_instances"></a>
|
||||||
## 解决实例之间的循环强引用
|
## 解决实例之间的循环强引用
|
||||||
@ -202,17 +202,17 @@ Swift 提供了两种办法用来解决你在使用类的属性时所遇到的
|
|||||||
<a name="weak_references"></a>
|
<a name="weak_references"></a>
|
||||||
### 弱引用
|
### 弱引用
|
||||||
|
|
||||||
*弱引用*不会对其引用的实例保持强引用,因而不会阻止 ARC 销毁被引用的实例。这个特性阻止了引用变为循环强引用。声明属性或者变量时,在前面加上`weak`关键字表明这是一个弱引用。
|
*弱引用*不会对其引用的实例保持强引用,因而不会阻止 ARC 销毁被引用的实例。这个特性阻止了引用变为循环强引用。声明属性或者变量时,在前面加上 `weak` 关键字表明这是一个弱引用。
|
||||||
|
|
||||||
因为弱引用不会保持所引用的实例,即使引用存在,实例也有可能被销毁。因此,ARC 会在引用的实例被销毁后自动将其赋值为`nil`。并且因为弱引用可以允许它们的值在运行时被赋值为`nil`,所以它们会被定义为可选类型变量,而不是常量。
|
因为弱引用不会保持所引用的实例,即使引用存在,实例也有可能被销毁。因此,ARC 会在引用的实例被销毁后自动将其赋值为 `nil`。并且因为弱引用可以允许它们的值在运行时被赋值为 `nil`,所以它们会被定义为可选类型变量,而不是常量。
|
||||||
|
|
||||||
你可以像其他可选值一样,检查弱引用的值是否存在,你将永远不会访问已销毁的实例的引用。
|
你可以像其他可选值一样,检查弱引用的值是否存在,你将永远不会访问已销毁的实例的引用。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 当 ARC 设置弱引用为`nil`时,属性观察不会被触发。
|
> 当 ARC 设置弱引用为 `nil` 时,属性观察不会被触发。
|
||||||
|
|
||||||
下面的例子跟上面`Person`和`Apartment`的例子一致,但是有一个重要的区别。这一次,`Apartment`的`tenant`属性被声明为弱引用:
|
下面的例子跟上面 `Person` 和 `Apartment` 的例子一致,但是有一个重要的区别。这一次,`Apartment` 的 `tenant` 属性被声明为弱引用:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Person {
|
class Person {
|
||||||
@ -230,7 +230,7 @@ class Apartment {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
然后跟之前一样,建立两个变量(`john`和`unit4A`)之间的强引用,并关联两个实例:
|
然后跟之前一样,建立两个变量(`john` 和 `unit4A`)之间的强引用,并关联两个实例:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var john: Person?
|
var john: Person?
|
||||||
@ -247,53 +247,54 @@ unit4A!.tenant = john
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
`Person`实例依然保持对`Apartment`实例的强引用,但是`Apartment`实例只持有对`Person`实例的弱引用。这意味着当你断开`john`变量所保持的强引用时,再也没有指向`Person`实例的强引用了:
|
`Person` 实例依然保持对 `Apartment` 实例的强引用,但是 `Apartment` 实例只持有对 `Person` 实例的弱引用。这意味着当你断开 `john` 变量所保持的强引用时,再也没有指向 `Person` 实例的强引用了:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
由于再也没有指向`Person`实例的强引用,该实例会被销毁:
|
由于再也没有指向 `Person` 实例的强引用,该实例会被销毁:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
john = nil
|
john = nil
|
||||||
// 打印 "John Appleseed is being deinitialized"
|
// 打印 "John Appleseed is being deinitialized"
|
||||||
```
|
```
|
||||||
|
|
||||||
唯一剩下的指向`Apartment`实例的强引用来自于变量`unit4A`。如果你断开这个强引用,再也没有指向`Apartment`实例的强引用了:
|
唯一剩下的指向 `Apartment` 实例的强引用来自于变量 `unit4A`。如果你断开这个强引用,再也没有指向 `Apartment` 实例的强引用了:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
由于再也没有指向`Apartment`实例的强引用,该实例也会被销毁:
|
由于再也没有指向 `Apartment` 实例的强引用,该实例也会被销毁:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
unit4A = nil
|
unit4A = nil
|
||||||
// 打印 "Apartment 4A is being deinitialized"
|
// 打印 "Apartment 4A is being deinitialized"
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的两段代码展示了变量`john`和`unit4A`在被赋值为`nil`后,`Person`实例和`Apartment`实例的析构函数都打印出“销毁”的信息。这证明了引用循环被打破了。
|
上面的两段代码展示了变量 `john` 和 `unit4A` 在被赋值为 `nil` 后,`Person` 实例和 `Apartment` 实例的析构函数都打印出“销毁”的信息。这证明了引用循环被打破了。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
在使用垃圾收集的系统里,弱指针有时用来实现简单的缓冲机制,因为没有强引用的对象只会在内存压力触发垃圾收集时才被销毁。但是在 ARC 中,一旦值的最后一个强引用被移除,就会被立即销毁,这导致弱引用并不适合上面的用途。
|
>
|
||||||
|
> 在使用垃圾收集的系统里,弱指针有时用来实现简单的缓冲机制,因为没有强引用的对象只会在内存压力触发垃圾收集时才被销毁。但是在 ARC 中,一旦值的最后一个强引用被移除,就会被立即销毁,这导致弱引用并不适合上面的用途。
|
||||||
|
|
||||||
<a name="unowned_references"></a>
|
<a name="unowned_references"></a>
|
||||||
### 无主引用
|
### 无主引用
|
||||||
|
|
||||||
和弱引用类似,*无主引用*不会牢牢保持住引用的实例。和弱引用不同的是,无主引用在其他实例有相同或者更长的生命周期时使用。你可以在声明属性或者变量时,在前面加上关键字`unowned`表示这是一个无主引用。
|
和弱引用类似,*无主引用*不会牢牢保持住引用的实例。和弱引用不同的是,无主引用在其他实例有相同或者更长的生命周期时使用。你可以在声明属性或者变量时,在前面加上关键字 `unowned` 表示这是一个无主引用。
|
||||||
|
|
||||||
无主引用通常都被期望拥有值。不过 ARC 无法在实例被销毁后将无主引用设为`nil`,因为非可选类型的变量不允许被赋值为`nil`。
|
无主引用通常都被期望拥有值。不过 ARC 无法在实例被销毁后将无主引用设为 `nil`,因为非可选类型的变量不允许被赋值为 `nil`。
|
||||||
|
|
||||||
> 重要
|
> 重点
|
||||||
>
|
>
|
||||||
> 使用无主引用,你*必须*确保引用始终指向一个未销毁的实例。
|
> 使用无主引用,你*必须*确保引用始终指向一个未销毁的实例。
|
||||||
>
|
>
|
||||||
> 如果你试图在实例被销毁后,访问该实例的无主引用,会触发运行时错误。
|
> 如果你试图在实例被销毁后,访问该实例的无主引用,会触发运行时错误。
|
||||||
|
|
||||||
下面的例子定义了两个类,`Customer`和`CreditCard`,模拟了银行客户和客户的信用卡。这两个类中,每一个都将另外一个类的实例作为自身的属性。这种关系可能会造成循环强引用。
|
下面的例子定义了两个类,`Customer` 和 `CreditCard`,模拟了银行客户和客户的信用卡。这两个类中,每一个都将另外一个类的实例作为自身的属性。这种关系可能会造成循环强引用。
|
||||||
|
|
||||||
`Customer`和`CreditCard`之间的关系与前面弱引用例子中`Apartment`和`Person`的关系略微不同。在这个数据模型中,一个客户可能有或者没有信用卡,但是一张信用卡总是关联着一个客户。为了表示这种关系,`Customer`类有一个可选类型的`card`属性,但是`CreditCard`类有一个非可选类型的`customer`属性。
|
`Customer` 和 `CreditCard` 之间的关系与前面弱引用例子中 `Apartment` 和 `Person` 的关系略微不同。在这个数据模型中,一个客户可能有或者没有信用卡,但是一张信用卡总是关联着一个客户。为了表示这种关系,`Customer` 类有一个可选类型的 `card` 属性,但是 `CreditCard` 类有一个非可选类型的 `customer` 属性。
|
||||||
|
|
||||||
此外,只能通过将一个`number`值和`customer`实例传递给`CreditCard`构造函数的方式来创建`CreditCard`实例。这样可以确保当创建`CreditCard`实例时总是有一个`customer`实例与之关联。
|
此外,只能通过将一个 `number` 值和 `customer` 实例传递给 `CreditCard` 构造函数的方式来创建 `CreditCard` 实例。这样可以确保当创建 `CreditCard` 实例时总是有一个 `customer` 实例与之关联。
|
||||||
|
|
||||||
由于信用卡总是关联着一个客户,因此将`customer`属性定义为无主引用,用以避免循环强引用:
|
由于信用卡总是关联着一个客户,因此将 `customer` 属性定义为无主引用,用以避免循环强引用:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Customer {
|
class Customer {
|
||||||
@ -318,15 +319,15 @@ class CreditCard {
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> `CreditCard`类的`number`属性被定义为`UInt64`类型而不是`Int`类型,以确保`number`属性的存储量在 32 位和 64 位系统上都能足够容纳 16 位的卡号。
|
> `CreditCard` 类的 `number` 属性被定义为 `UInt64` 类型而不是 `Int` 类型,以确保 `number` 属性的存储量在 32 位和 64 位系统上都能足够容纳 16 位的卡号。
|
||||||
|
|
||||||
下面的代码片段定义了一个叫`john`的可选类型`Customer`变量,用来保存某个特定客户的引用。由于是可选类型,所以变量被初始化为`nil`:
|
下面的代码片段定义了一个叫 `john` 的可选类型 `Customer` 变量,用来保存某个特定客户的引用。由于是可选类型,所以变量被初始化为 `nil`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var john: Customer?
|
var john: Customer?
|
||||||
```
|
```
|
||||||
|
|
||||||
现在你可以创建`Customer`类的实例,用它初始化`CreditCard`实例,并将新创建的`CreditCard`实例赋值为客户的`card`属性:
|
现在你可以创建 `Customer` 类的实例,用它初始化 `CreditCard` 实例,并将新创建的 `CreditCard` 实例赋值为客户的 `card` 属性:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
john = Customer(name: "John Appleseed")
|
john = Customer(name: "John Appleseed")
|
||||||
@ -337,13 +338,13 @@ john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
`Customer`实例持有对`CreditCard`实例的强引用,而`CreditCard`实例持有对`Customer`实例的无主引用。
|
`Customer` 实例持有对 `CreditCard` 实例的强引用,而 `CreditCard` 实例持有对 `Customer` 实例的无主引用。
|
||||||
|
|
||||||
由于`customer`的无主引用,当你断开`john`变量持有的强引用时,再也没有指向`Customer`实例的强引用了:
|
由于 `customer` 的无主引用,当你断开 `john` 变量持有的强引用时,再也没有指向 `Customer` 实例的强引用了:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
由于再也没有指向`Customer`实例的强引用,该实例被销毁了。其后,再也没有指向`CreditCard`实例的强引用,该实例也随之被销毁了:
|
由于再也没有指向 `Customer` 实例的强引用,该实例被销毁了。其后,再也没有指向 `CreditCard` 实例的强引用,该实例也随之被销毁了:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
john = nil
|
john = nil
|
||||||
@ -351,28 +352,26 @@ john = nil
|
|||||||
// 打印 "Card #1234567890123456 is being deinitialized"
|
// 打印 "Card #1234567890123456 is being deinitialized"
|
||||||
```
|
```
|
||||||
|
|
||||||
最后的代码展示了在`john`变量被设为`nil`后`Customer`实例和`CreditCard`实例的构造函数都打印出了“销毁”的信息。
|
最后的代码展示了在 `john` 变量被设为 `nil` 后 `Customer` 实例和 `CreditCard` 实例的构造函数都打印出了“销毁”的信息。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
> 上面的例子展示了如何使用安全的无主引用。对于需要禁用运行时的安全检查的情况(例如,出于性能方面的原因),Swift 还提供了不安全的无主引用。与所有不安全的操作一样,你需要负责检查代码以确保其安全性。
|
||||||
>上面的例子展示了如何使用安全的无主引用。对于需要禁用运行时的安全检查的情况(例如,出于性能方面的原因),Swift还提供了不安全的无主引用。与所有不安全的操作一样,你需要负责检查代码以确保其安全性。
|
> 你可以通过 `unowned(unsafe)` 来声明不安全无主引用。如果你试图在实例被销毁后,访问该实例的不安全无主引用,你的程序会尝试访问该实例之前所在的内存地址,这是一个不安全的操作。
|
||||||
>
|
|
||||||
>你可以通过`unowned(unsafe)`来声明不安全无主引用。如果你试图在实例被销毁后,访问该实例的不安全无主引用,你的程序会尝试访问该实例之前所在的内存地址,这是一个不安全的操作。
|
|
||||||
|
|
||||||
<a name="unowned_references_and_implicitly_unwrapped_optional_properties"></a>
|
<a name="unowned_references_and_implicitly_unwrapped_optional_properties"></a>
|
||||||
### 无主引用和隐式解析可选属性
|
### 无主引用和隐式解析可选属性
|
||||||
|
|
||||||
上面弱引用和无主引用的例子涵盖了两种常用的需要打破循环强引用的场景。
|
上面弱引用和无主引用的例子涵盖了两种常用的需要打破循环强引用的场景。
|
||||||
|
|
||||||
`Person`和`Apartment`的例子展示了两个属性的值都允许为`nil`,并会潜在的产生循环强引用。这种场景最适合用弱引用来解决。
|
`Person` 和 `Apartment` 的例子展示了两个属性的值都允许为 `nil`,并会潜在的产生循环强引用。这种场景最适合用弱引用来解决。
|
||||||
|
|
||||||
`Customer`和`CreditCard`的例子展示了一个属性的值允许为`nil`,而另一个属性的值不允许为`nil`,这也可能会产生循环强引用。这种场景最适合通过无主引用来解决。
|
`Customer` 和 `CreditCard` 的例子展示了一个属性的值允许为 `nil`,而另一个属性的值不允许为 `nil`,这也可能会产生循环强引用。这种场景最适合通过无主引用来解决。
|
||||||
|
|
||||||
然而,存在着第三种场景,在这种场景中,两个属性都必须有值,并且初始化完成后永远不会为`nil`。在这种场景中,需要一个类使用无主属性,而另外一个类使用隐式解析可选属性。
|
然而,存在着第三种场景,在这种场景中,两个属性都必须有值,并且初始化完成后永远不会为 `nil`。在这种场景中,需要一个类使用无主属性,而另外一个类使用隐式解析可选属性。
|
||||||
|
|
||||||
这使两个属性在初始化完成后能被直接访问(不需要可选展开),同时避免了循环引用。这一节将为你展示如何建立这种关系。
|
这使两个属性在初始化完成后能被直接访问(不需要可选展开),同时避免了循环引用。这一节将为你展示如何建立这种关系。
|
||||||
|
|
||||||
下面的例子定义了两个类,`Country`和`City`,每个类将另外一个类的实例保存为属性。在这个模型中,每个国家必须有首都,每个城市必须属于一个国家。为了实现这种关系,`Country`类拥有一个`capitalCity`属性,而`City`类有一个`country`属性:
|
下面的例子定义了两个类,`Country` 和 `City`,每个类将另外一个类的实例保存为属性。在这个模型中,每个国家必须有首都,每个城市必须属于一个国家。为了实现这种关系,`Country` 类拥有一个 `capitalCity` 属性,而 `City` 类有一个 `country` 属性:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class Country {
|
class Country {
|
||||||
@ -394,15 +393,15 @@ class City {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
为了建立两个类的依赖关系,`City`的构造函数接受一个`Country`实例作为参数,并且将实例保存到`country`属性。
|
为了建立两个类的依赖关系,`City` 的构造函数接受一个 `Country` 实例作为参数,并且将实例保存到 `country` 属性。
|
||||||
|
|
||||||
`Country`的构造函数调用了`City`的构造函数。然而,只有`Country`的实例完全初始化后,`Country`的构造函数才能把`self`传给`City`的构造函数。在[两段式构造过程](./14_Initialization.html#two_phase_initialization)中有具体描述。
|
`Country` 的构造函数调用了 `City` 的构造函数。然而,只有 `Country` 的实例完全初始化后,`Country` 的构造函数才能把 `self` 传给 `City` 的构造函数。在[两段式构造过程](./14_Initialization.html#two_phase_initialization)中有具体描述。
|
||||||
|
|
||||||
为了满足这种需求,通过在类型结尾处加上感叹号(`City!`)的方式,将`Country`的`capitalCity`属性声明为隐式解析可选类型的属性。这意味着像其他可选类型一样,`capitalCity`属性的默认值为`nil`,但是不需要展开它的值就能访问它。在[隐式解析可选类型](./01_The_Basics.html#implicityly_unwrapped_optionals)中有描述。
|
为了满足这种需求,通过在类型结尾处加上感叹号(`City!`)的方式,将 `Country` 的 `capitalCity` 属性声明为隐式解析可选类型的属性。这意味着像其他可选类型一样,`capitalCity` 属性的默认值为 `nil`,但是不需要展开它的值就能访问它。在[隐式解析可选类型](./01_The_Basics.html#implicityly_unwrapped_optionals)中有描述。
|
||||||
|
|
||||||
由于`capitalCity`默认值为`nil`,一旦`Country`的实例在构造函数中给`name`属性赋值后,整个初始化过程就完成了。这意味着一旦`name`属性被赋值后,`Country`的构造函数就能引用并传递隐式的`self`。`Country`的构造函数在赋值`capitalCity`时,就能将`self`作为参数传递给`City`的构造函数。
|
由于 `capitalCity` 默认值为 `nil`,一旦 `Country` 的实例在构造函数中给 `name` 属性赋值后,整个初始化过程就完成了。这意味着一旦 `name` 属性被赋值后,`Country` 的构造函数就能引用并传递隐式的 `self`。`Country` 的构造函数在赋值 `capitalCity` 时,就能将 `self` 作为参数传递给 `City` 的构造函数。
|
||||||
|
|
||||||
以上的意义在于你可以通过一条语句同时创建`Country`和`City`的实例,而不产生循环强引用,并且`capitalCity`的属性能被直接访问,而不需要通过感叹号来展开它的可选值:
|
以上的意义在于你可以通过一条语句同时创建 `Country` 和 `City` 的实例,而不产生循环强引用,并且 `capitalCity` 的属性能被直接访问,而不需要通过感叹号来展开它的可选值:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var country = Country(name: "Canada", capitalName: "Ottawa")
|
var country = Country(name: "Canada", capitalName: "Ottawa")
|
||||||
@ -410,20 +409,20 @@ print("\(country.name)'s capital city is called \(country.capitalCity.name)")
|
|||||||
// 打印 "Canada's capital city is called Ottawa"
|
// 打印 "Canada's capital city is called Ottawa"
|
||||||
```
|
```
|
||||||
|
|
||||||
在上面的例子中,使用隐式解析可选值意味着满足了类的构造函数的两个构造阶段的要求。`capitalCity`属性在初始化完成后,能像非可选值一样使用和存取,同时还避免了循环强引用。
|
在上面的例子中,使用隐式解析可选值意味着满足了类的构造函数的两个构造阶段的要求。`capitalCity` 属性在初始化完成后,能像非可选值一样使用和存取,同时还避免了循环强引用。
|
||||||
|
|
||||||
<a name="strong_reference_cycles_for_closures"></a>
|
<a name="strong_reference_cycles_for_closures"></a>
|
||||||
## 闭包的循环强引用
|
## 闭包的循环强引用
|
||||||
|
|
||||||
前面我们看到了循环强引用是在两个类实例属性互相保持对方的强引用时产生的,还知道了如何用弱引用和无主引用来打破这些循环强引用。
|
前面我们看到了循环强引用是在两个类实例属性互相保持对方的强引用时产生的,还知道了如何用弱引用和无主引用来打破这些循环强引用。
|
||||||
|
|
||||||
循环强引用还会发生在当你将一个闭包赋值给类实例的某个属性,并且这个闭包体中又使用了这个类实例时。这个闭包体中可能访问了实例的某个属性,例如`self.someProperty`,或者闭包中调用了实例的某个方法,例如`self.someMethod()`。这两种情况都导致了闭包“捕获”`self`,从而产生了循环强引用。
|
循环强引用还会发生在当你将一个闭包赋值给类实例的某个属性,并且这个闭包体中又使用了这个类实例时。这个闭包体中可能访问了实例的某个属性,例如 `self.someProperty`,或者闭包中调用了实例的某个方法,例如 `self.someMethod()`。这两种情况都导致了闭包“捕获”`self`,从而产生了循环强引用。
|
||||||
|
|
||||||
循环强引用的产生,是因为闭包和类相似,都是引用类型。当你把一个闭包赋值给某个属性时,你是将这个闭包的引用赋值给了属性。实质上,这跟之前的问题是一样的——两个强引用让彼此一直有效。但是,和两个类实例不同,这次一个是类实例,另一个是闭包。
|
循环强引用的产生,是因为闭包和类相似,都是引用类型。当你把一个闭包赋值给某个属性时,你是将这个闭包的引用赋值给了属性。实质上,这跟之前的问题是一样的——两个强引用让彼此一直有效。但是,和两个类实例不同,这次一个是类实例,另一个是闭包。
|
||||||
|
|
||||||
Swift 提供了一种优雅的方法来解决这个问题,称之为`闭包捕获列表`(closure capture list)。同样的,在学习如何用闭包捕获列表打破循环强引用之前,先来了解一下这里的循环强引用是如何产生的,这对我们很有帮助。
|
Swift 提供了一种优雅的方法来解决这个问题,称之为 `闭包捕获列表`(closure capture list)。同样的,在学习如何用闭包捕获列表打破循环强引用之前,先来了解一下这里的循环强引用是如何产生的,这对我们很有帮助。
|
||||||
|
|
||||||
下面的例子为你展示了当一个闭包引用了`self`后是如何产生一个循环强引用的。例子中定义了一个叫`HTMLElement`的类,用一种简单的模型表示 HTML 文档中的一个单独的元素:
|
下面的例子为你展示了当一个闭包引用了 `self` 后是如何产生一个循环强引用的。例子中定义了一个叫 `HTMLElement` 的类,用一种简单的模型表示 HTML 文档中的一个单独的元素:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class HTMLElement {
|
class HTMLElement {
|
||||||
@ -431,7 +430,7 @@ class HTMLElement {
|
|||||||
let name: String
|
let name: String
|
||||||
let text: String?
|
let text: String?
|
||||||
|
|
||||||
lazy var asHTML: Void -> String = {
|
lazy var asHTML: () -> String = {
|
||||||
if let text = self.text {
|
if let text = self.text {
|
||||||
return "<\(self.name)>\(text)</\(self.name)>"
|
return "<\(self.name)>\(text)</\(self.name)>"
|
||||||
} else {
|
} else {
|
||||||
@ -451,15 +450,15 @@ class HTMLElement {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`HTMLElement`类定义了一个`name`属性来表示这个元素的名称,例如代表头部元素的`"h1"`,代表段落的`"p"`,或者代表换行的`"br"`。`HTMLElement`还定义了一个可选属性`text`,用来设置 HTML 元素呈现的文本。
|
`HTMLElement` 类定义了一个 `name` 属性来表示这个元素的名称,例如代表头部元素的 `"h1"`,代表段落的 `"p"`,或者代表换行的 `"br"`。`HTMLElement` 还定义了一个可选属性 `text`,用来设置 HTML 元素呈现的文本。
|
||||||
|
|
||||||
除了上面的两个属性,`HTMLElement`还定义了一个`lazy`属性`asHTML`。这个属性引用了一个将`name`和`text`组合成 HTML 字符串片段的闭包。该属性是`Void -> String`类型,或者可以理解为“一个没有参数,返回`String`的函数”。
|
除了上面的两个属性,`HTMLElement` 还定义了一个 `lazy` 属性 `asHTML`。这个属性引用了一个将 `name` 和 `text` 组合成 HTML 字符串片段的闭包。该属性是 `Void -> String` 类型,或者可以理解为“一个没有参数,返回 `String` 的函数”。
|
||||||
|
|
||||||
默认情况下,闭包赋值给了`asHTML`属性,这个闭包返回一个代表 HTML 标签的字符串。如果`text`值存在,该标签就包含可选值`text`;如果`text`不存在,该标签就不包含文本。对于段落元素,根据`text`是`"some text"`还是`nil`,闭包会返回`"<p>some text</p>"`或者`"<p />"`。
|
默认情况下,闭包赋值给了 `asHTML` 属性,这个闭包返回一个代表 HTML 标签的字符串。如果 `text` 值存在,该标签就包含可选值 `text`;如果 `text` 不存在,该标签就不包含文本。对于段落元素,根据 `text` 是 `"some text"` 还是 `nil`,闭包会返回 `"<p>some text</p>"` 或者 `"<p />"`。
|
||||||
|
|
||||||
可以像实例方法那样去命名、使用`asHTML`属性。然而,由于`asHTML`是闭包而不是实例方法,如果你想改变特定 HTML 元素的处理方式的话,可以用自定义的闭包来取代默认值。
|
可以像实例方法那样去命名、使用 `asHTML` 属性。然而,由于 `asHTML` 是闭包而不是实例方法,如果你想改变特定 HTML 元素的处理方式的话,可以用自定义的闭包来取代默认值。
|
||||||
|
|
||||||
例如,可以将一个闭包赋值给`asHTML`属性,这个闭包能在`text`属性是`nil`时使用默认文本,这是为了避免返回一个空的 HTML 标签:
|
例如,可以将一个闭包赋值给 `asHTML` 属性,这个闭包能在 `text` 属性是 `nil` 时使用默认文本,这是为了避免返回一个空的 HTML 标签:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let heading = HTMLElement(name: "h1")
|
let heading = HTMLElement(name: "h1")
|
||||||
@ -473,11 +472,11 @@ print(heading.asHTML())
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> `asHTML`声明为`lazy`属性,因为只有当元素确实需要被处理为 HTML 输出的字符串时,才需要使用`asHTML`。也就是说,在默认的闭包中可以使用`self`,因为只有当初始化完成以及`self`确实存在后,才能访问`lazy`属性。
|
> `asHTML` 声明为 `lazy` 属性,因为只有当元素确实需要被处理为 HTML 输出的字符串时,才需要使用 `asHTML`。也就是说,在默认的闭包中可以使用 `self`,因为只有当初始化完成以及 `self` 确实存在后,才能访问 `lazy` 属性。
|
||||||
|
|
||||||
`HTMLElement`类只提供了一个构造函数,通过`name`和`text`(如果有的话)参数来初始化一个新元素。该类也定义了一个析构函数,当`HTMLElement`实例被销毁时,打印一条消息。
|
`HTMLElement` 类只提供了一个构造函数,通过 `name` 和 `text`(如果有的话)参数来初始化一个新元素。该类也定义了一个析构函数,当 `HTMLElement` 实例被销毁时,打印一条消息。
|
||||||
|
|
||||||
下面的代码展示了如何用`HTMLElement`类创建实例并打印消息:
|
下面的代码展示了如何用 `HTMLElement` 类创建实例并打印消息:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
|
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
|
||||||
@ -487,25 +486,25 @@ print(paragraph!.asHTML())
|
|||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 上面的`paragraph`变量定义为可选类型的`HTMLElement`,因此我们可以赋值`nil`给它来演示循环强引用。
|
> 上面的 `paragraph` 变量定义为可选类型的 `HTMLElement`,因此我们可以赋值 `nil` 给它来演示循环强引用。
|
||||||
|
|
||||||
不幸的是,上面写的`HTMLElement`类产生了类实例和作为`asHTML`默认值的闭包之间的循环强引用。循环强引用如下图所示:
|
不幸的是,上面写的 `HTMLElement` 类产生了类实例和作为 `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` 实例和它的闭包都不会被销毁,也是因为循环强引用:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
paragraph = nil
|
paragraph = nil
|
||||||
```
|
```
|
||||||
|
|
||||||
注意,`HTMLElement`的析构函数中的消息并没有被打印,证明了`HTMLElement`实例并没有被销毁。
|
注意,`HTMLElement` 的析构函数中的消息并没有被打印,证明了 `HTMLElement` 实例并没有被销毁。
|
||||||
|
|
||||||
<a name="resolving_strong_reference_cycles_for_closures"></a>
|
<a name="resolving_strong_reference_cycles_for_closures"></a>
|
||||||
## 解决闭包的循环强引用
|
## 解决闭包的循环强引用
|
||||||
@ -514,12 +513,12 @@ 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>
|
||||||
### 定义捕获列表
|
### 定义捕获列表
|
||||||
|
|
||||||
捕获列表中的每一项都由一对元素组成,一个元素是`weak`或`unowned`关键字,另一个元素是类实例的引用(例如`self`)或初始化过的变量(如`delegate = self.delegate!`)。这些项在方括号中用逗号分开。
|
捕获列表中的每一项都由一对元素组成,一个元素是 `weak` 或 `unowned` 关键字,另一个元素是类实例的引用(例如 `self`)或初始化过的变量(如 `delegate = self.delegate!`)。这些项在方括号中用逗号分开。
|
||||||
|
|
||||||
如果闭包有参数列表和返回类型,把捕获列表放在它们前面:
|
如果闭包有参数列表和返回类型,把捕获列表放在它们前面:
|
||||||
|
|
||||||
@ -530,7 +529,7 @@ lazy var someClosure: (Int, String) -> String = {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
如果闭包没有指明参数列表或者返回类型,即它们会通过上下文推断,那么可以把捕获列表和关键字`in`放在闭包最开始的地方:
|
如果闭包没有指明参数列表或者返回类型,它们会通过上下文推断,那么可以把捕获列表和关键字 `in` 放在闭包最开始的地方:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
lazy var someClosure: Void -> String = {
|
lazy var someClosure: Void -> String = {
|
||||||
@ -542,15 +541,15 @@ lazy var someClosure: Void -> String = {
|
|||||||
<a name="weak_and_unowned_references"></a>
|
<a name="weak_and_unowned_references"></a>
|
||||||
### 弱引用和无主引用
|
### 弱引用和无主引用
|
||||||
|
|
||||||
在闭包和捕获的实例总是互相引用并且总是同时销毁时,将闭包内的捕获定义为`无主引用`。
|
在闭包和捕获的实例总是互相引用并且总是同时销毁时,将闭包内的捕获定义为 `无主引用`。
|
||||||
|
|
||||||
相反的,在被捕获的引用可能会变为`nil`时,将闭包内的捕获定义为`弱引用`。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为`nil`。这使我们可以在闭包体内检查它们是否存在。
|
相反的,在被捕获的引用可能会变为 `nil` 时,将闭包内的捕获定义为 `弱引用`。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为 `nil`。这使我们可以在闭包体内检查它们是否存在。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
> 如果被捕获的引用绝对不会变为`nil`,应该用无主引用,而不是弱引用。
|
> 如果被捕获的引用绝对不会变为 `nil`,应该用无主引用,而不是弱引用。
|
||||||
|
|
||||||
前面的`HTMLElement`例子中,无主引用是正确的解决循环强引用的方法。这样编写`HTMLElement`类来避免循环强引用:
|
前面的 `HTMLElement` 例子中,无主引用是正确的解决循环强引用的方法。这样编写 `HTMLElement` 类来避免循环强引用:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class HTMLElement {
|
class HTMLElement {
|
||||||
@ -579,9 +578,9 @@ class HTMLElement {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
上面的`HTMLElement`实现和之前的实现一致,除了在`asHTML`闭包中多了一个捕获列表。这里,捕获列表是`[unowned self]`,表示“将`self`捕获为无主引用而不是强引用”。
|
上面的 `HTMLElement` 实现和之前的实现一致,除了在 `asHTML` 闭包中多了一个捕获列表。这里,捕获列表是 `[unowned self]`,表示“将 `self` 捕获为无主引用而不是强引用”。
|
||||||
|
|
||||||
和之前一样,我们可以创建并打印`HTMLElement`实例:
|
和之前一样,我们可以创建并打印 `HTMLElement` 实例:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
|
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
|
||||||
@ -593,7 +592,7 @@ print(paragraph!.asHTML())
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
这一次,闭包以无主引用的形式捕获`self`,并不会持有`HTMLElement`实例的强引用。如果将`paragraph`赋值为`nil`,`HTMLElement`实例将会被销毁,并能看到它的析构函数打印出的消息:
|
这一次,闭包以无主引用的形式捕获 `self`,并不会持有 `HTMLElement` 实例的强引用。如果将 `paragraph` 赋值为 `nil`,`HTMLElement` 实例将会被销毁,并能看到它的析构函数打印出的消息:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
paragraph = nil
|
paragraph = nil
|
||||||
|
|||||||
@ -7,11 +7,11 @@
|
|||||||
|
|
||||||
> 2.0
|
> 2.0
|
||||||
> 翻译+校对:[mmoaay](https://github.com/mmoaay)
|
> 翻译+校对:[mmoaay](https://github.com/mmoaay)
|
||||||
>
|
|
||||||
> 2.1
|
> 2.1
|
||||||
> 翻译:[Prayer](https://github.com/futantan)
|
> 翻译:[Prayer](https://github.com/futantan)
|
||||||
> 校对:[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
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ fileprivate func someFilePrivateFunction() {}
|
|||||||
private func somePrivateFunction() {}
|
private func somePrivateFunction() {}
|
||||||
```
|
```
|
||||||
|
|
||||||
除非专门指定,否则实体默认的访问级别为 `internal`,可以查阅[默认访问级别](#default_access_levels)这一节。这意味着在不使用修饰符显式声明访问级别的情况下,`SomeInternalClass` 和 `someInternalConstant` 仍然拥有隐式的 `internal` :
|
除非专门指定,否则实体默认的访问级别为 `internal`,可以查阅[默认访问级别](#default_access_levels)这一节。这意味着在不使用修饰符显式声明访问级别的情况下,`SomeInternalClass` 和 `someInternalConstant` 仍然拥有隐式的 `internal`:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class SomeInternalClass {} // 隐式 internal
|
class SomeInternalClass {} // 隐式 internal
|
||||||
@ -147,7 +147,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` 级别,那么你必须显式指定。这样做的好处是,在你定义公共接口的时候,可以明确地选择哪些接口是需要公开的,哪些是内部使用的,避免不小心将内部使用的接口公开。
|
||||||
|
|
||||||
@ -434,7 +434,7 @@ extension SomeStruct: SomeProtocol {
|
|||||||
<a name="type_aliases"></a>
|
<a name="type_aliases"></a>
|
||||||
## 类型别名
|
## 类型别名
|
||||||
|
|
||||||
你定义的任何类型别名都会被当作不同的类型,以便于进行访问控制。类型别名的访问级别不可高于其表示的类型的访问级别。例如,`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` 类型的别名。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
>
|
>
|
||||||
|
|||||||
@ -155,7 +155,7 @@ let blueComponent = pink & 0x0000FF // blueComponent 是 0x99,即 153
|
|||||||
|
|
||||||
红色部分是通过对 `0xCC6699` 和 `0xFF0000` 进行按位与运算后得到的。`0xFF0000` 中的 `0` 部分“掩盖”了 `OxCC6699` 中的第二、第三个字节,使得数值中的 `6699` 被忽略,只留下 `0xCC0000`。
|
红色部分是通过对 `0xCC6699` 和 `0xFF0000` 进行按位与运算后得到的。`0xFF0000` 中的 `0` 部分“掩盖”了 `OxCC6699` 中的第二、第三个字节,使得数值中的 `6699` 被忽略,只留下 `0xCC0000`。
|
||||||
|
|
||||||
然后,再将这个数按向右移动 16 位(`>> 16`)。十六进制中每两个字符表示 8 个比特位,所以移动 16 位后 `0xCC0000` 就变为 `0x0000CC`。这个数和`0xCC`是等同的,也就是十进制数值的 `204`。
|
然后,再将这个数按向右移动 16 位(`>> 16`)。十六进制中每两个字符表示 8 个比特位,所以移动 16 位后 `0xCC0000` 就变为 `0x0000CC`。这个数和 `0xCC` 是等同的,也就是十进制数值的 `204`。
|
||||||
|
|
||||||
同样的,绿色部分通过对 `0xCC6699` 和 `0x00FF00` 进行按位与运算得到 `0x006600`。然后将这个数向右移动 8 位,得到 `0x66`,也就是十进制数值的 `102`。
|
同样的,绿色部分通过对 `0xCC6699` 和 `0x00FF00` 进行按位与运算得到 `0x006600`。然后将这个数向右移动 8 位,得到 `0x66`,也就是十进制数值的 `102`。
|
||||||
|
|
||||||
@ -441,7 +441,7 @@ Swift 为以下自定义类型提等价运算符供合成实现:
|
|||||||
|
|
||||||
在类型原本的声明中声明遵循 `Equatable` 来接收这些默认实现。
|
在类型原本的声明中声明遵循 `Equatable` 来接收这些默认实现。
|
||||||
|
|
||||||
下面为三维位置向量 `(x, y, z)` 定义的 `Vector3D` 结构体,与 `Vector2D` 类似,由于 `x` , `y` 和 `z` 属性都是 `Equatable` 类型, `Vector3D` 就收到默认的等价运算符实现了。
|
下面为三维位置向量 `(x, y, z)` 定义的 `Vector3D` 结构体,与 `Vector2D` 类似,由于 `x`,`y` 和 `z` 属性都是 `Equatable` 类型,`Vector3D` 就收到默认的等价运算符实现了。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
struct Vector3D: Equatable {
|
struct Vector3D: Equatable {
|
||||||
|
|||||||
@ -57,11 +57,11 @@ Swift 的*“词法结构 (lexical structure)”* 描述了能构成该语言中
|
|||||||
> *注释* → // [*注释内容 断行*](#comment-text line-break)
|
> *注释* → // [*注释内容 断行*](#comment-text line-break)
|
||||||
> *多行注释* → `/*` [*多行注释内容*](#multiline-commnet-text) `*/`
|
> *多行注释* → `/*` [*多行注释内容*](#multiline-commnet-text) `*/`
|
||||||
> *注释内容* → [*注释内容项*](#comment-text-item) [*注释内容*](#comment-text)<sub>可选</sub>
|
> *注释内容* → [*注释内容项*](#comment-text-item) [*注释内容*](#comment-text)<sub>可选</sub>
|
||||||
> *注释内容项* → 任何Unicode标量值, 除了 U+000A 或者 U+000D
|
> *注释内容项* → 任何 Unicode 标量值, 除了 U+000A 或者 U+000D
|
||||||
> *多行注释内容* → [*多行注释内容项*](#multiline-comment-text-item) [*多行注释内容*](#multiline-comment-text)<sub>可选</sub>
|
> *多行注释内容* → [*多行注释内容项*](#multiline-comment-text-item) [*多行注释内容*](#multiline-comment-text)<sub>可选</sub>
|
||||||
> *多行注释内容项* → [*多行注释*](#multiline-comment).
|
> *多行注释内容项* → [*多行注释*](#multiline-comment).
|
||||||
> *多行注释内容项* → [*注释内容项*](#comment-text-item)
|
> *多行注释内容项* → [*注释内容项*](#comment-text-item)
|
||||||
> *多行注释内容项* → 任何Unicode标量值, 除了 `/*` 或者 `*/`
|
> *多行注释内容项* → 任何 Unicode 标量值, 除了 `/*` 或者 `*/`
|
||||||
|
|
||||||
注释可以包含额外的格式和标记,正如 [*Markup Formatting Reference*](https://developer.apple.com/library/prerelease/ios/documentation/Xcode/Reference/xcode_markup_formatting_ref/index.html#//apple_ref/doc/uid/TP40016497) 所述。
|
注释可以包含额外的格式和标记,正如 [*Markup Formatting Reference*](https://developer.apple.com/library/prerelease/ios/documentation/Xcode/Reference/xcode_markup_formatting_ref/index.html#//apple_ref/doc/uid/TP40016497) 所述。
|
||||||
|
|
||||||
@ -341,7 +341,7 @@ let textB = "Hello world"
|
|||||||
|
|
||||||
Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基础运算符](../chapter2/02_Basic_Operators.html) 和 [高级运算符](../chapter2/25_Advanced_Operators.html) 中进行了阐述。这一小节将描述哪些字符能用于自定义运算符。
|
Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基础运算符](../chapter2/02_Basic_Operators.html) 和 [高级运算符](../chapter2/25_Advanced_Operators.html) 中进行了阐述。这一小节将描述哪些字符能用于自定义运算符。
|
||||||
|
|
||||||
自定义运算符可以由以下其中之一的 ASCII 字符 `/`、`=`、 `-`、`+`、`!`、`*`、`%`、`<`、`>`、`&`、`|`、`^`、`?` 以及 `~`,或者后面语法中规定的任一个 Unicode 字符(其中包含了*数学运算符*、*零散符号(Miscellaneous Symbols)* 以及印刷符号 (Dingbats) 之类的 Unicode 块)开始。在第一个字符之后,允许使用组合型 Unicode 字符。
|
自定义运算符可以由以下其中之一的 ASCII 字符 `/`、`=`、`-`、`+`、`!`、`*`、`%`、`<`、`>`、`&`、`|`、`^`、`?` 以及 `~`,或者后面语法中规定的任一个 Unicode 字符(其中包含了*数学运算符*、*零散符号(Miscellaneous Symbols)* 以及印刷符号 (Dingbats) 之类的 Unicode 块)开始。在第一个字符之后,允许使用组合型 Unicode 字符。
|
||||||
|
|
||||||
您也可以以点号 (`.`) 开头来定义自定义运算符。这些运算符可以包含额外的点,例如 `.+.`。如果某个运算符不是以点号开头的,那么它就无法再包含另外的点号了。例如,`+.+` 就会被看作为一个 `+` 运算符后面跟着一个 `.+` 运算符。
|
您也可以以点号 (`.`) 开头来定义自定义运算符。这些运算符可以包含额外的点,例如 `.+.`。如果某个运算符不是以点号开头的,那么它就无法再包含另外的点号了。例如,`+.+` 就会被看作为一个 `+` 运算符后面跟着一个 `.+` 运算符。
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,7 @@ Swift 语言存在两种类型:命名型类型和复合型类型。命名型
|
|||||||
|
|
||||||
复合型类型是没有名字的类型,它由 Swift 本身定义。Swift 存在两种复合型类型:函数类型和元组类型。一个复合型类型可以包含命名型类型和其它复合型类型。例如,元组类型 `(Int, (Int, Int))` 包含两个元素:第一个是命名型类型 `Int`,第二个是另一个复合型类型 `(Int, Int)`。
|
复合型类型是没有名字的类型,它由 Swift 本身定义。Swift 存在两种复合型类型:函数类型和元组类型。一个复合型类型可以包含命名型类型和其它复合型类型。例如,元组类型 `(Int, (Int, Int))` 包含两个元素:第一个是命名型类型 `Int`,第二个是另一个复合型类型 `(Int, Int)`。
|
||||||
|
|
||||||
你可以在命名型类型和复合型类型使用小括号。但是在类型旁加小括号没有任何作用。举个例子,`(Int)`等同于`Int`。
|
你可以在命名型类型和复合型类型使用小括号。但是在类型旁加小括号没有任何作用。举个例子,`(Int)` 等同于 `Int`。
|
||||||
|
|
||||||
本节讨论 Swift 语言本身定义的类型,并描述 Swift 中的类型推断行为。
|
本节讨论 Swift 语言本身定义的类型,并描述 Swift 中的类型推断行为。
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ someTuple = (9, 99) // 正确:命名类型被自动推断
|
|||||||
someTuple = (left: 5, right: 5) // 错误:命名类型不匹配
|
someTuple = (left: 5, right: 5) // 错误:命名类型不匹配
|
||||||
```
|
```
|
||||||
|
|
||||||
所有的元组类型都包含两个及以上元素, 除了`Void`。 `Void` 是空元组类型 `()` 的别名。
|
所有的元组类型都包含两个及以上元素, 除了 `Void`。`Void` 是空元组类型 `()` 的别名。
|
||||||
|
|
||||||
> 元组类型语法
|
> 元组类型语法
|
||||||
>
|
>
|
||||||
@ -138,13 +138,13 @@ someTuple = (left: 5, right: 5) // 错误:命名类型不匹配
|
|||||||
|
|
||||||
参数类型是由逗号间隔的类型列表。由于参数类型和返回值类型可以是元组类型,所以函数类型支持多参数与多返回值的函数与方法。
|
参数类型是由逗号间隔的类型列表。由于参数类型和返回值类型可以是元组类型,所以函数类型支持多参数与多返回值的函数与方法。
|
||||||
|
|
||||||
你可以对函数参数`() - > T `(其中 T 是任何类型)使用 `autoclosure` 特性。这会自动将参数表达式转化为闭包,表达式的结果即闭包返回值。这从语法结构上提供了一种便捷:延迟对表达式的求值,直到其值在函数体中被调用。以自动闭包做为参数的函数类型的例子详见 [自动闭包](../chapter2/07_Closures.html#autoclosures) 。
|
你可以对函数参数 `() -> T`(其中 T 是任何类型)使用 `autoclosure` 特性。这会自动将参数表达式转化为闭包,表达式的结果即闭包返回值。这从语法结构上提供了一种便捷:延迟对表达式的求值,直到其值在函数体中被调用。以自动闭包做为参数的函数类型的例子详见 [自动闭包](../chapter2/07_Closures.html#autoclosures) 。
|
||||||
|
|
||||||
函数类型可以拥有一个可变长参数作为参数类型中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字紧随三个点(`...`)组成,如 `Int...`。可变长参数被认为是一个包含了基础类型元素的数组。即 `Int...` 就是 `[Int]`。关于使用可变长参数的例子,请参阅 [可变参数](../chapter2/06_Functions.html#variadic_parameters)。
|
函数类型可以拥有一个可变长参数作为参数类型中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字紧随三个点(`...`)组成,如 `Int...`。可变长参数被认为是一个包含了基础类型元素的数组。即 `Int...` 就是 `[Int]`。关于使用可变长参数的例子,请参阅 [可变参数](../chapter2/06_Functions.html#variadic_parameters)。
|
||||||
|
|
||||||
为了指定一个 `in-out` 参数,可以在参数类型前加 `inout` 前缀。但是你不可以对可变长参数或返回值类型使用 `inout`。关于这种参数的详细讲解请参阅 [输入输出参数](../chapter2/06_Functions.html#in_out_parameters)。
|
为了指定一个 `in-out` 参数,可以在参数类型前加 `inout` 前缀。但是你不可以对可变长参数或返回值类型使用 `inout`。关于这种参数的详细讲解请参阅 [输入输出参数](../chapter2/06_Functions.html#in_out_parameters)。
|
||||||
|
|
||||||
如果一个函数类型只有一个形式参数而且形式参数的类型是元组类型,那么元组类型在写函数类型的时候必须用圆括号括起来。比如说, `((Int, Int)) -> Void` 是接收一个元组 `(Int, Int)` 作为形式参数的函数的类型。与此相反,不加括号的`(Int, Int) -> Void` 是一个接收两个 `Int` 形式参数并且不返回任何值的函数的类型。相似地,因为`Void` 是空元组类型 `()` 的别名, 函数类型`(Void)-> Void`与一个空元组的变量的函数类型`(()) -> ()`是一样的。但这些类型和无变量的函数类型`() -> ()`是不一样的。
|
如果一个函数类型只有一个形式参数而且形式参数的类型是元组类型,那么元组类型在写函数类型的时候必须用圆括号括起来。比如说,`((Int, Int)) -> Void` 是接收一个元组 `(Int, Int)` 作为形式参数的函数的类型。与此相反,不加括号的 `(Int, Int) -> Void` 是一个接收两个 `Int` 形式参数并且不返回任何值的函数的类型。相似地,因为 `Void` 是空元组类型 `()` 的别名, 函数类型 `(Void)-> Void` 与一个空元组的变量的函数类型 `(()) -> ()` 是一样的。但这些类型和无变量的函数类型 `() -> ()` 是不一样的。
|
||||||
|
|
||||||
函数和方法中的变量名并不是函数类型的一部分。例如:
|
函数和方法中的变量名并不是函数类型的一部分。例如:
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ func someFunction(left: Int, right: Int) {}
|
|||||||
func anotherFunction(left: Int, right: Int) {}
|
func anotherFunction(left: Int, right: Int) {}
|
||||||
func functionWithDifferentLabels(top: Int, bottom: Int) {}
|
func functionWithDifferentLabels(top: Int, bottom: Int) {}
|
||||||
|
|
||||||
var f = someFunction // 函数f的类型为 (Int, Int) -> Void, 而不是 (left: Int, right: Int) -> Void.
|
var f = someFunction // 函数 f 的类型为 (Int, Int) -> Void, 而不是 (left: Int, right: Int) -> Void.
|
||||||
f = anotherFunction // 正确
|
f = anotherFunction // 正确
|
||||||
f = functionWithDifferentLabels // 正确
|
f = functionWithDifferentLabels // 正确
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ var operation: (Int, Int) -> Int // 正确
|
|||||||
|
|
||||||
<a name="Restrictions for Nonescaping Closures"></a>
|
<a name="Restrictions for Nonescaping Closures"></a>
|
||||||
### 对非逃逸闭包的限制
|
### 对非逃逸闭包的限制
|
||||||
非逃逸闭包函数不能作为参数传递到另一个非逃逸闭包函数的参数。这样的限制可以让Swift在编译时就完成更多的内存访问冲突检查, 而不是在运行时。举个例子:
|
非逃逸闭包函数不能作为参数传递到另一个非逃逸闭包函数的参数。这样的限制可以让 Swift 在编译时就完成更多的内存访问冲突检查, 而不是在运行时。举个例子:
|
||||||
|
|
||||||
```
|
```
|
||||||
let external: (Any) -> Void = { _ in () }
|
let external: (Any) -> Void = { _ in () }
|
||||||
@ -193,11 +193,11 @@ func takesTwoFunctions(first: (Any) -> Void, second: (Any) -> Void) {
|
|||||||
external(first) // 正确
|
external(first) // 正确
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
在上面代码里,`takesTwoFunctions(first:second:)`的两个参数都是函数。 它们都没有标记为`@escaping`, 因此它们都是非逃逸的。
|
在上面代码里,`takesTwoFunctions(first:second:)` 的两个参数都是函数。 它们都没有标记为 `@escaping`, 因此它们都是非逃逸的。
|
||||||
|
|
||||||
上述例子里的被标记为“错误”的四个函数调用会产生编译错误。因为第一个和第二个参数是非逃逸函数,它们不能够被当作变量被传递到另一个非闭包函数参数。与此相反, 标记“正确”的两个函数不回产生编译错误。这些函数调用不会违反限制, 因为`外部(external)`不是`takesTwoFunctions(first:second:)`里的一个参数。
|
上述例子里的被标记为“错误”的四个函数调用会产生编译错误。因为第一个和第二个参数是非逃逸函数,它们不能够被当作变量被传递到另一个非闭包函数参数。与此相反, 标记“正确”的两个函数不回产生编译错误。这些函数调用不会违反限制, 因为 `外部(external)` 不是 `takesTwoFunctions(first:second:)` 里的一个参数。
|
||||||
|
|
||||||
如果你需要避免这个限制, 标记其中之一的参数为逃逸, 或者使用`withoutActuallyEscaping(_:do:)`函数临时地转换非逃逸函数的其中一个参数为逃逸函数。关于避免内存访问冲突,可以参阅[内存安全](../chapter2/24_Memory_Safety.html)。
|
如果你需要避免这个限制, 标记其中之一的参数为逃逸, 或者使用 `withoutActuallyEscaping(_:do:)` 函数临时地转换非逃逸函数的其中一个参数为逃逸函数。关于避免内存访问冲突,可以参阅[内存安全](../chapter2/24_Memory_Safety.html)。
|
||||||
|
|
||||||
|
|
||||||
> 函数类型语法
|
> 函数类型语法
|
||||||
@ -327,7 +327,7 @@ let arrayOfImplicitlyUnwrappedElements: [Int!] // 错误
|
|||||||
let implicitlyUnwrappedArray: [Int]! // 正确
|
let implicitlyUnwrappedArray: [Int]! // 正确
|
||||||
```
|
```
|
||||||
|
|
||||||
由于隐式解析可选类型和可选类型有同样的表达式`Optional<Wrapped>`,你可以在使用可选类型的地方使用隐式解析可选类型。比如,你可以将隐式解析可选类型的值赋给变量、常量和可选属性,反之亦然。
|
由于隐式解析可选类型和可选类型有同样的表达式 `Optional<Wrapped>`,你可以在使用可选类型的地方使用隐式解析可选类型。比如,你可以将隐式解析可选类型的值赋给变量、常量和可选属性,反之亦然。
|
||||||
|
|
||||||
正如可选类型一样,你在声明隐式解析可选类型的变量或属性的时候也不用指定初始值,因为它有默认值 `nil`。
|
正如可选类型一样,你在声明隐式解析可选类型的变量或属性的时候也不用指定初始值,因为它有默认值 `nil`。
|
||||||
|
|
||||||
@ -349,7 +349,7 @@ let implicitlyUnwrappedArray: [Int]! // 正确
|
|||||||
|
|
||||||
> `Protocol 1` & `Procotol 2`
|
> `Protocol 1` & `Procotol 2`
|
||||||
|
|
||||||
协议合成类型允许你指定一个值,其类型符合多个协议的要求且不需要定义一个新的命名型协议来继承它想要符合的各个协议。比如,协议合成类型 `Protocol A & Protocol B & Protocol C` 等效于一个从 `Protocol A`,`Protocol B`, `Protocol C` 继承而来的新协议 `Protocol D`,很显然这样做有效率的多,甚至不需引入一个新名字。
|
协议合成类型允许你指定一个值,其类型符合多个协议的要求且不需要定义一个新的命名型协议来继承它想要符合的各个协议。比如,协议合成类型 `Protocol A & Protocol B & Protocol C` 等效于一个从 `Protocol A`,`Protocol B`,`Protocol C` 继承而来的新协议 `Protocol D`,很显然这样做有效率的多,甚至不需引入一个新名字。
|
||||||
|
|
||||||
协议合成列表中的每项必须是协议名或协议合成类型的类型别名。
|
协议合成列表中的每项必须是协议名或协议合成类型的类型别名。
|
||||||
|
|
||||||
@ -389,7 +389,7 @@ type(of: someInstance).printClassName()
|
|||||||
// 打印 “SomeSubClass”
|
// 打印 “SomeSubClass”
|
||||||
```
|
```
|
||||||
|
|
||||||
更多信息可以查看Swift标准库里的`type(of:)`。
|
更多信息可以查看 Swift 标准库里的 `type(of:)`。
|
||||||
|
|
||||||
可以使用初始化表达式从某个类型的元类型构造出一个该类型的实例。对于类实例,被调用的构造器必须使用 `required` 关键字标记,或者整个类使用 `final` 关键字标记。
|
可以使用初始化表达式从某个类型的元类型构造出一个该类型的实例。对于类实例,被调用的构造器必须使用 `required` 关键字标记,或者整个类使用 `final` 关键字标记。
|
||||||
|
|
||||||
|
|||||||
@ -54,7 +54,7 @@ Swift 中存在四种表达式:前缀表达式,二元表达式,基本表
|
|||||||
> 表达式语法
|
> 表达式语法
|
||||||
>
|
>
|
||||||
<a name="expression"></a>
|
<a name="expression"></a>
|
||||||
> *表达式* → [*try运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression) [*二元表达式列表*](#binary-expressions)<sub>可选</sub>
|
> *表达式* → [*try 运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression) [*二元表达式列表*](#binary-expressions)<sub>可选</sub>
|
||||||
<a name="expression-list"></a>
|
<a name="expression-list"></a>
|
||||||
> *表达式列表* → [*表达式*](#expression) | [*表达式*](#expression) **,** [*表达式列表*](#expression-list)
|
> *表达式列表* → [*表达式*](#expression) | [*表达式*](#expression) **,** [*表达式列表*](#expression-list)
|
||||||
|
|
||||||
@ -131,8 +131,8 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误:try
|
|||||||
> 二元表达式语法
|
> 二元表达式语法
|
||||||
>
|
>
|
||||||
> *二元表达式* → [*二元运算符*](02_Lexical_Structure.md#binary-operator) [*前缀表达式*](#prefix-expression)
|
> *二元表达式* → [*二元运算符*](02_Lexical_Structure.md#binary-operator) [*前缀表达式*](#prefix-expression)
|
||||||
> *二元表达式* → [*赋值运算符*](#assignment-operator) [*try运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression)
|
> *二元表达式* → [*赋值运算符*](#assignment-operator) [*try 运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression)
|
||||||
> *二元表达式* → [*条件运算符*](#conditional-operator) [*try运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression)
|
> *二元表达式* → [*条件运算符*](#conditional-operator) [*try 运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression)
|
||||||
> *二元表达式* → [*类型转换运算符*](#type-casting-operator)
|
> *二元表达式* → [*类型转换运算符*](#type-casting-operator)
|
||||||
<a name="binary-expressions"></a>
|
<a name="binary-expressions"></a>
|
||||||
> *二元表达式列表* → [*二元表达式*](#binary-expression) [*二元表达式列表*](#binary-expressions)<sub>可选</sub>
|
> *二元表达式列表* → [*二元表达式*](#binary-expression) [*二元表达式列表*](#binary-expressions)<sub>可选</sub>
|
||||||
@ -172,17 +172,20 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误:try
|
|||||||
> 三元条件运算符语法
|
> 三元条件运算符语法
|
||||||
>
|
>
|
||||||
<a name="conditional-operator"></a>
|
<a name="conditional-operator"></a>
|
||||||
> *三元条件运算符* → **?** [try运算符](#try-operator)<sub>可选</sub> [*表达式*](#expression) **:**
|
> *三元条件运算符* → **?** [try 运算符](#try-operator)<sub>可选</sub> [*表达式*](#expression) **:**
|
||||||
|
|
||||||
<a name="type-casting_operators"></a>
|
<a name="type-casting_operators"></a>
|
||||||
### 类型转换运算符
|
### 类型转换运算符
|
||||||
|
|
||||||
有 4 种类型转换运算符:`is`、`as`、`as? `和`as!`。它们有如下的形式:
|
有 4 种类型转换运算符:`is`、`as`、`as? ` 和 `as!`。它们有如下的形式:
|
||||||
|
|
||||||
> `表达式` is `类型`
|
> `表达式` is `类型`
|
||||||
`表达式` as `类型`
|
>
|
||||||
`表达式` as? `类型`
|
> `表达式` as `类型`
|
||||||
`表达式` as! `类型`
|
>
|
||||||
|
> `表达式` as? `类型`
|
||||||
|
>
|
||||||
|
> `表达式` as! `类型`
|
||||||
|
|
||||||
`is` 运算符在运行时检查表达式能否向下转化为指定的类型,如果可以则返回 `ture`,否则返回 `false`。
|
`is` 运算符在运行时检查表达式能否向下转化为指定的类型,如果可以则返回 `ture`,否则返回 `false`。
|
||||||
|
|
||||||
@ -229,7 +232,7 @@ f(x as Any)
|
|||||||
<a name="primary-expression"></a>
|
<a name="primary-expression"></a>
|
||||||
> *基本表达式* → [*标识符*](02_Lexical_Structure.md#identifier) [*泛型实参子句*](08_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub>
|
> *基本表达式* → [*标识符*](02_Lexical_Structure.md#identifier) [*泛型实参子句*](08_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub>
|
||||||
> *基本表达式* → [*字面量表达式*](#literal-expression)
|
> *基本表达式* → [*字面量表达式*](#literal-expression)
|
||||||
> *基本表达式* → [*self表达式*](#self-expression)
|
> *基本表达式* → [*self 表达式*](#self-expression)
|
||||||
> *基本表达式* → [*超类表达式*](#superclass-expression)
|
> *基本表达式* → [*超类表达式*](#superclass-expression)
|
||||||
> *基本表达式* → [*闭包表达式*](#closure-expression)
|
> *基本表达式* → [*闭包表达式*](#closure-expression)
|
||||||
> *基本表达式* → [*圆括号表达式*](#parenthesized-expression)
|
> *基本表达式* → [*圆括号表达式*](#parenthesized-expression)
|
||||||
@ -249,7 +252,7 @@ f(x as Any)
|
|||||||
`#column` | `Int` | 所在的列数
|
`#column` | `Int` | 所在的列数
|
||||||
`#function` | `String` | 所在的声明的名字
|
`#function` | `String` | 所在的声明的名字
|
||||||
|
|
||||||
`#line`除了上述含义外,还有另一种含义。当它出现在单独一行时,会被理解成行控制语句,请参阅[线路控制语句](../chapter3/10_Statements.md#线路控制语句)。
|
`#line` 除了上述含义外,还有另一种含义。当它出现在单独一行时,会被理解成行控制语句,请参阅[线路控制语句](../chapter3/10_Statements.md#线路控制语句)。
|
||||||
|
|
||||||
对于 `#function`,在函数中会返回当前函数的名字,在方法中会返回当前方法的名字,在属性的存取器中会返回属性的名字,在特殊的成员如 `init` 或 `subscript` 中会返回这个关键字的名字,在某个文件中会返回当前模块的名字。
|
对于 `#function`,在函数中会返回当前函数的名字,在方法中会返回当前方法的名字,在属性的存取器中会返回属性的名字,在特殊的成员如 `init` 或 `subscript` 中会返回这个关键字的名字,在某个文件中会返回当前模块的名字。
|
||||||
|
|
||||||
@ -520,7 +523,7 @@ x = .AnotherValue
|
|||||||
<a name="parenthesized_expression"></a>
|
<a name="parenthesized_expression"></a>
|
||||||
### 圆括号表达式
|
### 圆括号表达式
|
||||||
|
|
||||||
*圆括号表达式*是由圆括号包围的表达式。你可以用圆括号说明成组的表达式的先后操作。成组的圆括号不会改变表达式的类型 - 例如`(1)`的类型就是简单的`Int`。
|
*圆括号表达式*是由圆括号包围的表达式。你可以用圆括号说明成组的表达式的先后操作。成组的圆括号不会改变表达式的类型 - 例如 `(1)` 的类型就是简单的 `Int`。
|
||||||
|
|
||||||
> 圆括号表达式语法
|
> 圆括号表达式语法
|
||||||
>
|
>
|
||||||
@ -563,7 +566,7 @@ x = .AnotherValue
|
|||||||
<a name="selector_expression"></a>
|
<a name="selector_expression"></a>
|
||||||
### 选择器表达式
|
### 选择器表达式
|
||||||
|
|
||||||
选择器表达式可以让你通过选择器来引用在Objective-C中方法(method)和属性(property)的setter和getter方法。
|
选择器表达式可以让你通过选择器来引用在 Objective-C 中方法(method)和属性(property)的 setter 和 getter 方法。
|
||||||
|
|
||||||
> \#selector(方法名)
|
> \#selector(方法名)
|
||||||
\#selector(getter: 属性名)
|
\#selector(getter: 属性名)
|
||||||
@ -584,9 +587,9 @@ class SomeClass: NSObject {
|
|||||||
let selectorForMethod = #selector(SomeClass.doSomething(_:))
|
let selectorForMethod = #selector(SomeClass.doSomething(_:))
|
||||||
let selectorForPropertyGetter = #selector(getter: SomeClass.property)
|
let selectorForPropertyGetter = #selector(getter: SomeClass.property)
|
||||||
```
|
```
|
||||||
当为属性的getter创建选择器时,属性名可以是变量属性或者常量属性的引用。但是当为属性的setter创建选择器时,属性名只可以是对变量属性的引用。
|
当为属性的 getter 创建选择器时,属性名可以是变量属性或者常量属性的引用。但是当为属性的 setter 创建选择器时,属性名只可以是对变量属性的引用。
|
||||||
|
|
||||||
方法名称可以包含圆括号来进行分组,并使用as 操作符来区分具有相同方法名但类型不同的方法,例如:
|
方法名称可以包含圆括号来进行分组,并使用 as 操作符来区分具有相同方法名但类型不同的方法,例如:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
extension SomeClass {
|
extension SomeClass {
|
||||||
@ -599,6 +602,7 @@ let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (Str
|
|||||||
由于选择器是在编译时创建的,因此编译器可以检查方法或者属性是否存在,以及是否在运行时暴露给了 Objective-C 。
|
由于选择器是在编译时创建的,因此编译器可以检查方法或者属性是否存在,以及是否在运行时暴露给了 Objective-C 。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
|
>
|
||||||
> 虽然方法名或者属性名是个表达式,但是它不会被求值。
|
> 虽然方法名或者属性名是个表达式,但是它不会被求值。
|
||||||
|
|
||||||
更多关于如何在 Swift 代码中使用选择器来与 Objective-C API 进行交互的信息,请参阅 [Using Swift with Cocoa and Objective-C (Swift 3)](https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中[Objective-C Selectors](https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-ID59)部分。
|
更多关于如何在 Swift 代码中使用选择器来与 Objective-C API 进行交互的信息,请参阅 [Using Swift with Cocoa and Objective-C (Swift 3)](https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中[Objective-C Selectors](https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-ID59)部分。
|
||||||
|
|||||||
@ -93,7 +93,7 @@ for item in collection {
|
|||||||
> for-in 语句语法
|
> for-in 语句语法
|
||||||
>
|
>
|
||||||
<a name="for-in-statement"></a>
|
<a name="for-in-statement"></a>
|
||||||
> *for-in 语句* → **for** **case**<sub>可选</sub> [*模式*](07_Patterns.md#pattern) **in** [*表达式*](04_Expressions.md#expression) [*where子句*](#where-clause)<sub>可选</sub> [*代码块*](05_Declarations.md#code-block)
|
> *for-in 语句* → **for** **case**<sub>可选</sub> [*模式*](07_Patterns.md#pattern) **in** [*表达式*](04_Expressions.md#expression) [*where 子句*](#where-clause)<sub>可选</sub> [*代码块*](05_Declarations.md#code-block)
|
||||||
|
|
||||||
<a name="while_statements"></a>
|
<a name="while_statements"></a>
|
||||||
### While 语句
|
### While 语句
|
||||||
@ -115,7 +115,7 @@ while condition {
|
|||||||
|
|
||||||
由于会在执行循环体中的语句前判断条件的值,因此循环体中的语句可能会被执行若干次,也可能一次也不会被执行。
|
由于会在执行循环体中的语句前判断条件的值,因此循环体中的语句可能会被执行若干次,也可能一次也不会被执行。
|
||||||
|
|
||||||
条件的结果必须是Bool类型或者Bool的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
|
条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
|
||||||
|
|
||||||
> while 语句语法
|
> while 语句语法
|
||||||
>
|
>
|
||||||
@ -125,7 +125,7 @@ while condition {
|
|||||||
<a name="condition-clause"></a>
|
<a name="condition-clause"></a>
|
||||||
> *条件子句* → [*表达式*](04_Expressions.md#expression) | [*表达式*](04_Expressions.md#expression) **,** [*条件列表*](#condition-list)
|
> *条件子句* → [*表达式*](04_Expressions.md#expression) | [*表达式*](04_Expressions.md#expression) **,** [*条件列表*](#condition-list)
|
||||||
<a name="condition"></a>
|
<a name="condition"></a>
|
||||||
> *条件* → [*表达式*](04_Expressions.md#expression) |[*可用性条件*](#availability-condition) | [*case条件*](#case-condition) | [*可选绑定条件*](#optional-binding-condition)
|
> *条件* → [*表达式*](04_Expressions.md#expression) |[*可用性条件*](#availability-condition) | [*case 条件*](#case-condition) | [*可选绑定条件*](#optional-binding-condition)
|
||||||
<a name="case-condition"></a>
|
<a name="case-condition"></a>
|
||||||
> *case 条件* → **case** [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer)
|
> *case 条件* → **case** [*模式*](07_Patterns.md#pattern) [*构造器*](05_Declarations.md#initializer)
|
||||||
<a name="optional-binding-condition"></a>
|
<a name="optional-binding-condition"></a>
|
||||||
@ -151,7 +151,7 @@ repeat {
|
|||||||
|
|
||||||
由于条件的值是在循环体中的语句执行后才进行判断,因此循环体中的语句至少会被执行一次。
|
由于条件的值是在循环体中的语句执行后才进行判断,因此循环体中的语句至少会被执行一次。
|
||||||
|
|
||||||
条件的结果必须是Bool类型或者Bool的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
|
条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
|
||||||
|
|
||||||
> repeat-while 语句语法
|
> repeat-while 语句语法
|
||||||
>
|
>
|
||||||
@ -209,14 +209,14 @@ if condition 1 {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`if` 语句中条件的结果必须是Bool类型或者Bool的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
|
`if` 语句中条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
|
||||||
|
|
||||||
> if 语句语法
|
> if 语句语法
|
||||||
>
|
>
|
||||||
<a name="if-statement"></a>
|
<a name="if-statement"></a>
|
||||||
> *if 语句* → **if** [*条件子句*](#condition-clause) [*代码块*](05_Declarations.md#code-block) [*else子句*](#else-clause)<sub>可选</sub>
|
> *if 语句* → **if** [*条件子句*](#condition-clause) [*代码块*](05_Declarations.md#code-block) [*else 子句*](#else-clause)<sub>可选</sub>
|
||||||
<a name="else-clause"></a>
|
<a name="else-clause"></a>
|
||||||
> *else 子句* → **else** [*代码块*](05_Declarations.md#code-block) | **else** [*if语句*](#if-statement)
|
> *else 子句* → **else** [*代码块*](05_Declarations.md#code-block) | **else** [*if 语句*](#if-statement)
|
||||||
|
|
||||||
<a name="guard_statements"></a>
|
<a name="guard_statements"></a>
|
||||||
### Guard 语句
|
### Guard 语句
|
||||||
@ -231,7 +231,7 @@ guard condition else {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`guard` 语句中条件的结果必须是Bool类型或者Bool的桥接类型。另外,条件也可以是一条可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.html#optional_binding)。
|
`guard` 语句中条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件也可以是一条可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.html#optional_binding)。
|
||||||
|
|
||||||
在 `guard` 语句中进行可选绑定的常量或者变量,其可用范围从声明开始直到作用域结束。
|
在 `guard` 语句中进行可选绑定的常量或者变量,其可用范围从声明开始直到作用域结束。
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ guard condition else {
|
|||||||
* `continue`
|
* `continue`
|
||||||
* `throw`
|
* `throw`
|
||||||
|
|
||||||
关于控制转移语句,请参阅 [控制转移语句](#control_transfer_statements)。关于`Never`返回类型的函数,请参阅 [永不返回的函数](05_Declarations.md#rethrowing_functions_and_methods)。
|
关于控制转移语句,请参阅 [控制转移语句](#control_transfer_statements)。关于 `Never` 返回类型的函数,请参阅 [永不返回的函数](05_Declarations.md#rethrowing_functions_and_methods)。
|
||||||
|
|
||||||
> guard 语句语法
|
> guard 语句语法
|
||||||
>
|
>
|
||||||
@ -297,21 +297,21 @@ case let (x, y) where x == y:
|
|||||||
> switch 语句语法
|
> switch 语句语法
|
||||||
>
|
>
|
||||||
<a name="switch-statement"></a>
|
<a name="switch-statement"></a>
|
||||||
> *switch 语句* → **switch** [*表达式*](04_Expressions.md#expression) **{** [*switch-case列表*](#switch-cases)<sub>可选</sub> **}**
|
> *switch 语句* → **switch** [*表达式*](04_Expressions.md#expression) **{** [*switch-case 列表*](#switch-cases)<sub>可选</sub> **}**
|
||||||
<a name="switch-cases"></a>
|
<a name="switch-cases"></a>
|
||||||
> *switch case 列表* → [*switch-case*](#switch-case) [*switch-case列表*](#switch-cases)<sub>可选</sub>
|
> *switch case 列表* → [*switch-case*](#switch-case) [*switch-case 列表*](#switch-cases)<sub>可选</sub>
|
||||||
<a name="switch-case"></a>
|
<a name="switch-case"></a>
|
||||||
> *switch case* → [*case标签*](#case-label) [*多条语句*](#statements) | [*default标签*](#default-label) [*多条语句*](#statements)
|
> *switch case* → [*case 标签*](#case-label) [*多条语句*](#statements) | [*default 标签*](#default-label) [*多条语句*](#statements)
|
||||||
|
|
||||||
<a name="case-label"></a>
|
<a name="case-label"></a>
|
||||||
> *case 标签* → **case** [*case项列表*](#case-item-list) **:**
|
> *case 标签* → **case** [*case 项列表*](#case-item-list) **:**
|
||||||
<a name="case-item-list"></a>
|
<a name="case-item-list"></a>
|
||||||
> *case 项列表* → [*模式*](07_Patterns.md#pattern) [*where子句*](#where-clause)<sub>可选</sub> | [*模式*](07_Patterns.md#pattern) [*where子句*](#where-clause)<sub>可选</sub> **,** [*case项列表*](#case-item-list)
|
> *case 项列表* → [*模式*](07_Patterns.md#pattern) [*where 子句*](#where-clause)<sub>可选</sub> | [*模式*](07_Patterns.md#pattern) [*where 子句*](#where-clause)<sub>可选</sub> **,** [*case 项列表*](#case-item-list)
|
||||||
<a name="default-label"></a>
|
<a name="default-label"></a>
|
||||||
> *default 标签* → **default** **:**
|
> *default 标签* → **default** **:**
|
||||||
|
|
||||||
<a name="where-clause"></a>
|
<a name="where-clause"></a>
|
||||||
> *where-clause* → **where** [*where表达式*](#where-expression)
|
> *where-clause* → **where** [*where 表达式*](#where-expression)
|
||||||
<a name="where-expression"></a>
|
<a name="where-expression"></a>
|
||||||
> *where-expression* → [*表达式*](04_Expressions.md#expression)
|
> *where-expression* → [*表达式*](04_Expressions.md#expression)
|
||||||
|
|
||||||
@ -327,7 +327,7 @@ case let (x, y) where x == y:
|
|||||||
> 带标签的语句语法
|
> 带标签的语句语法
|
||||||
>
|
>
|
||||||
<a name="labeled-statement"></a>
|
<a name="labeled-statement"></a>
|
||||||
> *带标签的语句* → [*语句标签*](#statement-label) [*循环语句*](#loop-statement) | [*语句标签*](#statement-label) [*if语句*](#if-statement) | [*语句标签*](#statement-label) [*switch语句*](#switch-statement)
|
> *带标签的语句* → [*语句标签*](#statement-label) [*循环语句*](#loop-statement) | [*语句标签*](#statement-label) [*if 语句*](#if-statement) | [*语句标签*](#statement-label) [*switch 语句*](#switch-statement)
|
||||||
<a name="statement-label"></a>
|
<a name="statement-label"></a>
|
||||||
> *语句标签* → [*标签名称*](#label-name) **:**
|
> *语句标签* → [*标签名称*](#label-name) **:**
|
||||||
<a name="label-name"></a>
|
<a name="label-name"></a>
|
||||||
@ -513,11 +513,11 @@ do {
|
|||||||
> do 语句语法
|
> do 语句语法
|
||||||
>
|
>
|
||||||
<a name="do-statement"></a>
|
<a name="do-statement"></a>
|
||||||
> *do 语句* → **do** [*代码块*](05_Declarations.md#code-block) [*多条 catch子句*](#catch-clauses)<sub>可选</sub>
|
> *do 语句* → **do** [*代码块*](05_Declarations.md#code-block) [*多条 catch 子句*](#catch-clauses)<sub>可选</sub>
|
||||||
<a name="catch-clauses"></a>
|
<a name="catch-clauses"></a>
|
||||||
> *多条 catch 子句* → [*catch子句*](#catch-clause) [*多条 catch子句*](#catch-clauses)<sub>可选</sub>
|
> *多条 catch 子句* → [*catch 子句*](#catch-clause) [*多条 catch 子句*](#catch-clauses)<sub>可选</sub>
|
||||||
<a name="catch-clause"></a>
|
<a name="catch-clause"></a>
|
||||||
> *catch 子句* → **catch** [*模式*](07_Patterns.md#pattern)<sub>可选</sub> [*where子句*](#where-clause)<sub>可选</sub> [*代码块*](05_Declarations.md#code-block)
|
> *catch 子句* → **catch** [*模式*](07_Patterns.md#pattern)<sub>可选</sub> [*where 子句*](#where-clause)<sub>可选</sub> [*代码块*](05_Declarations.md#code-block)
|
||||||
|
|
||||||
<a name="compiler_control_statements"></a>
|
<a name="compiler_control_statements"></a>
|
||||||
## 编译器控制语句
|
## 编译器控制语句
|
||||||
@ -581,9 +581,9 @@ statements to compile if both compilation conditions are false
|
|||||||
> 编译配置语句语法
|
> 编译配置语句语法
|
||||||
>
|
>
|
||||||
<a name="build-configuration-statement"></a>
|
<a name="build-configuration-statement"></a>
|
||||||
> *单个编译配置语句* → **#if** [*编译配置*](#build-configuration) [*语句*](#statements)<sub>可选</sub> [*多个编译配置elseif子句*](#build-configuration-elseif-clauses)<sub>可选</sub> **-** [*单个编译配置else子句*](#build-configuration-else-clause)<sub>可选</sub> **#endif**
|
> *单个编译配置语句* → **#if** [*编译配置*](#build-configuration) [*语句*](#statements)<sub>可选</sub> [*多个编译配置 elseif 子句*](#build-configuration-elseif-clauses)<sub>可选</sub> **-** [*单个编译配置 else 子句*](#build-configuration-else-clause)<sub>可选</sub> **#endif**
|
||||||
<a name="build-configuration-elseif-clauses"></a>
|
<a name="build-configuration-elseif-clauses"></a>
|
||||||
> *多个编译配置 elseif 子句* → [*单个编译配置elseif子句*](#build-configuration-elseif-clause) [*多个编译配置elseif子句*](build-configuration-elseif-clauses)<sub>可选</sub>
|
> *多个编译配置 elseif 子句* → [*单个编译配置 elseif 子句*](#build-configuration-elseif-clause) [*多个编译配置 elseif 子句*](build-configuration-elseif-clauses)<sub>可选</sub>
|
||||||
<a name="build-configuration-elseif-clause"></a>
|
<a name="build-configuration-elseif-clause"></a>
|
||||||
> *单个编译配置 elseif 子句* → **#elseif** [*编译配置*](#build-configuration) [*语句*](#statements)<sub>可选</sub>
|
> *单个编译配置 elseif 子句* → **#elseif** [*编译配置*](#build-configuration) [*语句*](#statements)<sub>可选</sub>
|
||||||
<a name="build-configuration-else-clause"></a>
|
<a name="build-configuration-else-clause"></a>
|
||||||
@ -603,7 +603,7 @@ statements to compile if both compilation conditions are false
|
|||||||
> *平台检测函数* → **os** **(** [*操作系统*](#operating-system) **)**
|
> *平台检测函数* → **os** **(** [*操作系统*](#operating-system) **)**
|
||||||
> *平台检测函数* → **arch** **(** [*架构*](#architecture) **)**
|
> *平台检测函数* → **arch** **(** [*架构*](#architecture) **)**
|
||||||
<a name="language-version-testing-function"></a>
|
<a name="language-version-testing-function"></a>
|
||||||
> *语言版本检测函数* → **swift** **(** **>=** [*swift版本*](#swift-version) **)**
|
> *语言版本检测函数* → **swift** **(** **>=** [*swift 版本*](#swift-version) **)**
|
||||||
<a name="operating-system"></a>
|
<a name="operating-system"></a>
|
||||||
> *操作系统* → **OSX** | **iOS** | **watchOS** | **tvOS**
|
> *操作系统* → **OSX** | **iOS** | **watchOS** | **tvOS**
|
||||||
<a name="architecture"></a>
|
<a name="architecture"></a>
|
||||||
|
|||||||
@ -188,6 +188,7 @@ print("The second number is \(secondNumber).")
|
|||||||
变量声明有几种不同的形式,可以声明不同种类的命名值和可变值,如存储型和计算型变量和属性,属性观察器,以及静态变量属性。所使用的声明形式取决于变量声明的适用范围和打算声明的变量类型。
|
变量声明有几种不同的形式,可以声明不同种类的命名值和可变值,如存储型和计算型变量和属性,属性观察器,以及静态变量属性。所使用的声明形式取决于变量声明的适用范围和打算声明的变量类型。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
|
>
|
||||||
> 也可以在协议声明中声明属性,详情请参阅 [协议属性声明](#protocol_property_declaration)。
|
> 也可以在协议声明中声明属性,详情请参阅 [协议属性声明](#protocol_property_declaration)。
|
||||||
|
|
||||||
可以在子类中重写继承来的变量属性,使用 `override` 声明修饰符标记属性的声明即可,详情请参阅 [重写](../chapter2/13_Inheritance.md#overriding)。
|
可以在子类中重写继承来的变量属性,使用 `override` 声明修饰符标记属性的声明即可,详情请参阅 [重写](../chapter2/13_Inheritance.md#overriding)。
|
||||||
@ -274,6 +275,7 @@ var 变量名称: 类型 = 表达式 {
|
|||||||
要声明一个类型变量属性,用 `static` 声明修饰符标记该声明。类可以改用 `class` 声明修饰符标记类的类型计算型属性从而允许子类重写超类的实现。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties) 章节有详细讨论。
|
要声明一个类型变量属性,用 `static` 声明修饰符标记该声明。类可以改用 `class` 声明修饰符标记类的类型计算型属性从而允许子类重写超类的实现。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties) 章节有详细讨论。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
|
>
|
||||||
> 在一个类声明中,使用关键字 `static` 与同时使用 `class` 和 `final` 去标记一个声明的效果相同。
|
> 在一个类声明中,使用关键字 `static` 与同时使用 `class` 和 `final` 去标记一个声明的效果相同。
|
||||||
|
|
||||||
<a name="grammer_of_a_variable_declaration"></a>
|
<a name="grammer_of_a_variable_declaration"></a>
|
||||||
@ -282,10 +284,10 @@ var 变量名称: 类型 = 表达式 {
|
|||||||
<a name="variable-declaration"></a>
|
<a name="variable-declaration"></a>
|
||||||
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*模式构造器列表*](#pattern-initializer-list)
|
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*模式构造器列表*](#pattern-initializer-list)
|
||||||
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型标注*](03_Types.md#type-annotation) [*代码块*](#code-block)
|
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型标注*](03_Types.md#type-annotation) [*代码块*](#code-block)
|
||||||
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型标注*](03_Types.md#type-annotation) [*getter-setter代码块*](#getter-setter-block)
|
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型标注*](03_Types.md#type-annotation) [*getter-setter 代码块*](#getter-setter-block)
|
||||||
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型标注*](03_Types.md#type-annotation) [*getter-setter关键字代码块*](#getter-setter-keyword-block)
|
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型标注*](03_Types.md#type-annotation) [*getter-setter 关键字代码块*](#getter-setter-keyword-block)
|
||||||
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*构造器*](#initializer) [*willSet-didSet代码块*](#willSet-didSet-block)
|
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*构造器*](#initializer) [*willSet-didSet 代码块*](#willSet-didSet-block)
|
||||||
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型标注*](03_Types.md#type-annotation) [*构造器*](#initializer)<sub>可选</sub> [*willSet-didSet代码块*](#willSet-didSet-block)
|
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型标注*](03_Types.md#type-annotation) [*构造器*](#initializer)<sub>可选</sub> [*willSet-didSet 代码块*](#willSet-didSet-block)
|
||||||
|
|
||||||
<a name="variable-declaration-head"></a>
|
<a name="variable-declaration-head"></a>
|
||||||
> *变量声明头* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> [*声明修饰符列表*](#declaration-modifiers)<sub>可选</sub> **var**
|
> *变量声明头* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> [*声明修饰符列表*](#declaration-modifiers)<sub>可选</sub> **var**
|
||||||
@ -294,30 +296,30 @@ var 变量名称: 类型 = 表达式 {
|
|||||||
|
|
||||||
<a name="getter-setter-block"></a>
|
<a name="getter-setter-block"></a>
|
||||||
> *getter-setter 代码块* → [*代码块*](#code-block)
|
> *getter-setter 代码块* → [*代码块*](#code-block)
|
||||||
> *getter-setter 代码块* → **{** [*getter子句*](#getter-clause) [*setter子句*](#setter-clause)<sub>可选</sub> **}**
|
> *getter-setter 代码块* → **{** [*getter 子句*](#getter-clause) [*setter 子句*](#setter-clause)<sub>可选</sub> **}**
|
||||||
> *getter-setter 代码块* → **{** [*setter子句*](#setter-clause) [*getter子句*](#getter-clause) **}**
|
> *getter-setter 代码块* → **{** [*setter 子句*](#setter-clause) [*getter 子句*](#getter-clause) **}**
|
||||||
> <a name="getter-clause"></a>
|
> <a name="getter-clause"></a>
|
||||||
> *getter 子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **get** [*代码块*](#code-block)
|
> *getter 子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **get** [*代码块*](#code-block)
|
||||||
> <a name="setter-clause"></a>
|
> <a name="setter-clause"></a>
|
||||||
> *setter 子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **set** [*setter名称*](#setter-name)<sub>可选</sub> [*代码块*](#code-block)
|
> *setter 子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **set** [*setter 名称*](#setter-name)<sub>可选</sub> [*代码块*](#code-block)
|
||||||
> <a name="setter-name"></a>
|
> <a name="setter-name"></a>
|
||||||
> *setter 名称* → **(** [*标识符*](02_Lexical_Structure.md#identifier) **)**
|
> *setter 名称* → **(** [*标识符*](02_Lexical_Structure.md#identifier) **)**
|
||||||
|
|
||||||
<a name="getter-setter-keyword-block"></a>
|
<a name="getter-setter-keyword-block"></a>
|
||||||
> *getter-setter 关键字代码块* → **{** [*getter关键字子句*](#getter-keyword-clause) [*setter关键字子句*](#setter-keyword-clause)<sub>可选</sub> **}**
|
> *getter-setter 关键字代码块* → **{** [*getter 关键字子句*](#getter-keyword-clause) [*setter 关键字子句*](#setter-keyword-clause)<sub>可选</sub> **}**
|
||||||
> *getter-setter 关键字代码块* → **{** [*setter关键字子句*](#setter-keyword-clause) [*getter关键字子句*](#getter-keyword-clause) **}**
|
> *getter-setter 关键字代码块* → **{** [*setter 关键字子句*](#setter-keyword-clause) [*getter 关键字子句*](#getter-keyword-clause) **}**
|
||||||
> <a name="getter-keyword-clause"></a>
|
> <a name="getter-keyword-clause"></a>
|
||||||
> *getter 关键字子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **get**
|
> *getter 关键字子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **get**
|
||||||
> <a name="setter-keyword-clause"></a>
|
> <a name="setter-keyword-clause"></a>
|
||||||
> *setter 关键字子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **set**
|
> *setter 关键字子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **set**
|
||||||
|
|
||||||
<a name="willSet-didSet-block"></a>
|
<a name="willSet-didSet-block"></a>
|
||||||
> *willSet-didSet 代码块* → **{** [*willSet子句*](#willSet-clause) [*didSet子句*](#didSet-clause)<sub>可选</sub> **}**
|
> *willSet-didSet 代码块* → **{** [*willSet 子句*](#willSet-clause) [*didSet 子句*](#didSet-clause)<sub>可选</sub> **}**
|
||||||
> *willSet-didSet 代码块* → **{** [*didSet子句*](#didSet-clause) [*willSet子句*](#willSet-clause)<sub>可选</sub> **}**
|
> *willSet-didSet 代码块* → **{** [*didSet 子句*](#didSet-clause) [*willSet 子句*](#willSet-clause)<sub>可选</sub> **}**
|
||||||
> <a name="willSet-clause"></a>
|
> <a name="willSet-clause"></a>
|
||||||
> *willSet 子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **willSet** [*setter名称*](#setter-name)<sub>可选</sub> [*代码块*](#code-block)
|
> *willSet 子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **willSet** [*setter 名称*](#setter-name)<sub>可选</sub> [*代码块*](#code-block)
|
||||||
> <a name="didSet-clause"></a>
|
> <a name="didSet-clause"></a>
|
||||||
> *didSet 子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **didSet** [*setter名称*](#setter-name)<sub>可选</sub> [*代码块*](#code-block)
|
> *didSet 子句* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> **didSet** [*setter 名称*](#setter-name)<sub>可选</sub> [*代码块*](#code-block)
|
||||||
|
|
||||||
<a name="type_alias_declaration"></a>
|
<a name="type_alias_declaration"></a>
|
||||||
## 类型别名声明
|
## 类型别名声明
|
||||||
@ -353,7 +355,7 @@ func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
|
|||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
假如没有类型别名,sum函数将必须引用关联类型通过T.Iterator.Element的形式来替代 T.Element。
|
假如没有类型别名,sum 函数将必须引用关联类型通过 T.Iterator.Element 的形式来替代 T.Element。
|
||||||
|
|
||||||
另请参阅 [协议关联类型声明](#protocol_associated_type_declaration)。
|
另请参阅 [协议关联类型声明](#protocol_associated_type_declaration)。
|
||||||
|
|
||||||
@ -538,9 +540,9 @@ func someFunction(callback: () throws -> Void) rethrows {
|
|||||||
<a name="functions_that_never_return"></a>
|
<a name="functions_that_never_return"></a>
|
||||||
### 永不返回的函数
|
### 永不返回的函数
|
||||||
|
|
||||||
Swift定义了`Never`类型,它表示函数或者方法不会返回给它的调用者。`Never`返回类型的函数或方法可以称为不归,不归函数、方法要么引发不可恢复的错误,要么永远不停地运作,这会使调用后本应执行得代码就不再执行了。但即使是不归函数、方法,抛错函数和重抛出函数也可以将程序控制转移到合适的`catch`代码块。
|
Swift 定义了 `Never` 类型,它表示函数或者方法不会返回给它的调用者。`Never` 返回类型的函数或方法可以称为不归,不归函数、方法要么引发不可恢复的错误,要么永远不停地运作,这会使调用后本应执行得代码就不再执行了。但即使是不归函数、方法,抛错函数和重抛出函数也可以将程序控制转移到合适的 `catch` 代码块。
|
||||||
|
|
||||||
不归函数、方法可以在guard语句的else字句中调用,具体讨论在[*Guard语句*](10_Statements.md#guard_statements)。
|
不归函数、方法可以在 guard 语句的 else 字句中调用,具体讨论在[*Guard 语句*](10_Statements.md#guard_statements)。
|
||||||
你可以重载一个不归方法,但是新的方法必须保持原有的返回类型和没有返回的行为。
|
你可以重载一个不归方法,但是新的方法必须保持原有的返回类型和没有返回的行为。
|
||||||
|
|
||||||
<a name="grammer_of_a_function_declaration"></a>
|
<a name="grammer_of_a_function_declaration"></a>
|
||||||
@ -830,6 +832,7 @@ protocol 协议名称: 继承的协议 {
|
|||||||
协议类型可以继承自任意数量的其它协议。当一个协议类型继承自其它协议的时候,来自其它协议的所有要求会聚合在一起,而且采纳当前协议的类型必须符合所有的这些要求。关于如何使用协议继承的例子,请参阅 [协议继承](../chapter2/22_Protocols.md#protocol_inheritance)。
|
协议类型可以继承自任意数量的其它协议。当一个协议类型继承自其它协议的时候,来自其它协议的所有要求会聚合在一起,而且采纳当前协议的类型必须符合所有的这些要求。关于如何使用协议继承的例子,请参阅 [协议继承](../chapter2/22_Protocols.md#protocol_inheritance)。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
|
>
|
||||||
> 也可以使用协议合成类型来聚合多个协议的一致性要求,请参阅 [协议合成类型](03_Types.md#protocol_composition_type) 和 [协议合成](../chapter2/22_Protocols.md#protocol_composition)。
|
> 也可以使用协议合成类型来聚合多个协议的一致性要求,请参阅 [协议合成类型](03_Types.md#protocol_composition_type) 和 [协议合成](../chapter2/22_Protocols.md#protocol_composition)。
|
||||||
|
|
||||||
可以通过类型的扩展声明来采纳协议,从而为之前声明的类型添加协议一致性。在扩展中,必须实现所有采纳协议的要求。如果该类型已经实现了所有的要求,可以让这个扩展声明的主体留空。
|
可以通过类型的扩展声明来采纳协议,从而为之前声明的类型添加协议一致性。在扩展中,必须实现所有采纳协议的要求。如果该类型已经实现了所有的要求,可以让这个扩展声明的主体留空。
|
||||||
@ -847,6 +850,7 @@ protocol SomeProtocol: class {
|
|||||||
任何继承自标记有 `class` 关键字的协议的协议也仅能被类类型采纳。
|
任何继承自标记有 `class` 关键字的协议的协议也仅能被类类型采纳。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
|
>
|
||||||
> 如果协议已经用 `objc` 特性标记了,`class` 要求就隐式地应用于该协议,无需显式使用 `class` 关键字。
|
> 如果协议已经用 `objc` 特性标记了,`class` 要求就隐式地应用于该协议,无需显式使用 `class` 关键字。
|
||||||
|
|
||||||
协议类型是命名的类型,因此它们可以像其他命名类型一样使用,正如 [协议作为类型](../chapter2/22_Protocols.md#protocols_as_types) 所讨论的。然而,不能构造一个协议的实例,因为协议实际上不提供它们指定的要求的实现。
|
协议类型是命名的类型,因此它们可以像其他命名类型一样使用,正如 [协议作为类型](../chapter2/22_Protocols.md#protocols_as_types) 所讨论的。然而,不能构造一个协议的实例,因为协议实际上不提供它们指定的要求的实现。
|
||||||
@ -890,7 +894,7 @@ var 属性名: 类型 { get set }
|
|||||||
<a name="grammer_of_an_import_declaration"></a>
|
<a name="grammer_of_an_import_declaration"></a>
|
||||||
> 协议属性声明语法
|
> 协议属性声明语法
|
||||||
> <a name="protocol-property-declaration"></a>
|
> <a name="protocol-property-declaration"></a>
|
||||||
> *协议属性声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型标注*](03_Types.md#type-annotation) [*getter-setter关键字代码块*](#getter-setter-keyword-block)
|
> *协议属性声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型标注*](03_Types.md#type-annotation) [*getter-setter 关键字代码块*](#getter-setter-keyword-block)
|
||||||
|
|
||||||
<a name="protocol_method_declaration"></a>
|
<a name="protocol_method_declaration"></a>
|
||||||
### 协议方法声明
|
### 协议方法声明
|
||||||
@ -940,7 +944,7 @@ subscript (参数列表) -> 返回类型 { get set }
|
|||||||
<a name="grammer_of_a_protocol_subscript_declaration"></a>
|
<a name="grammer_of_a_protocol_subscript_declaration"></a>
|
||||||
> 协议下标声明语法
|
> 协议下标声明语法
|
||||||
> <a name="protocol-subscript-declaration"></a>
|
> <a name="protocol-subscript-declaration"></a>
|
||||||
> *协议下标声明* → [*下标头*](#subscript-head) [*下标结果*](#subscript-result) [*getter-setter关键字代码块*](#getter-setter-keyword-block)
|
> *协议下标声明* → [*下标头*](#subscript-head) [*下标结果*](#subscript-result) [*getter-setter 关键字代码块*](#getter-setter-keyword-block)
|
||||||
|
|
||||||
<a name="protocol_associated_type_declaration"></a>
|
<a name="protocol_associated_type_declaration"></a>
|
||||||
### 协议关联类型声明
|
### 协议关联类型声明
|
||||||
@ -992,6 +996,7 @@ convenience init(参数列表) {
|
|||||||
和方法、属性和下标一样,需要使用 `override` 声明修饰符标记重写的指定构造器。
|
和方法、属性和下标一样,需要使用 `override` 声明修饰符标记重写的指定构造器。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
|
>
|
||||||
> 如果使用 `required` 声明修饰符标记一个构造器,在子类中重写这种构造器时,无需使用 `override` 修饰符。
|
> 如果使用 `required` 声明修饰符标记一个构造器,在子类中重写这种构造器时,无需使用 `override` 修饰符。
|
||||||
|
|
||||||
就像函数和方法,构造器也可以抛出或者重抛错误,你可以在构造器参数列表的圆括号之后使用 `throws` 或 `rethrows` 关键字来表明相应的抛出行为。
|
就像函数和方法,构造器也可以抛出或者重抛错误,你可以在构造器参数列表的圆括号之后使用 `throws` 或 `rethrows` 关键字来表明相应的抛出行为。
|
||||||
@ -1085,6 +1090,7 @@ extension 类型名称: 采纳的协议 {
|
|||||||
声明语句
|
声明语句
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
extension 类型名称 where 要求 {
|
extension 类型名称 where 要求 {
|
||||||
声明语句
|
声明语句
|
||||||
@ -1092,7 +1098,7 @@ extension 类型名称 where 要求 {
|
|||||||
```
|
```
|
||||||
扩展声明体可包含零个或多个声明语句。这些声明语句可以包括计算型属性、计算型类型属性、实例方法、类型方法、构造器、下标声明,甚至是类、结构体和枚举声明。扩展声明不能包含析构器、协议声明、存储型属性、属性观察器或其他扩展声明。关于扩展声明的详细讨论,以及各种扩展声明的例子,请参阅 [扩展](../chapter2/21_Extensions.md)。
|
扩展声明体可包含零个或多个声明语句。这些声明语句可以包括计算型属性、计算型类型属性、实例方法、类型方法、构造器、下标声明,甚至是类、结构体和枚举声明。扩展声明不能包含析构器、协议声明、存储型属性、属性观察器或其他扩展声明。关于扩展声明的详细讨论,以及各种扩展声明的例子,请参阅 [扩展](../chapter2/21_Extensions.md)。
|
||||||
|
|
||||||
如果类型为类,结构体,或枚举类型,则扩展声明会扩展相应的类型。如果类型为协议类型,则扩展声明会扩展所有遵守这个协议的类型。在扩展的协议体中声明语句不能使用`final`标识符。
|
如果类型为类,结构体,或枚举类型,则扩展声明会扩展相应的类型。如果类型为协议类型,则扩展声明会扩展所有遵守这个协议的类型。在扩展的协议体中声明语句不能使用 `final` 标识符。
|
||||||
|
|
||||||
扩展声明可以为现存的类、结构体、枚举添加协议一致性,但是不能为类添加超类,因此在扩展声明的类型名称的冒号后面仅能指定一个协议列表。
|
扩展声明可以为现存的类、结构体、枚举添加协议一致性,但是不能为类添加超类,因此在扩展声明的类型名称的冒号后面仅能指定一个协议列表。
|
||||||
|
|
||||||
@ -1144,8 +1150,8 @@ subscript (参数列表) -> 返回类型 {
|
|||||||
> 下标声明语法
|
> 下标声明语法
|
||||||
> <a name="subscript-declaration"></a>
|
> <a name="subscript-declaration"></a>
|
||||||
> *下标声明* → [*下标头*](#subscript-head) [*下标结果*](#subscript-result) [*代码块*](#code-block)
|
> *下标声明* → [*下标头*](#subscript-head) [*下标结果*](#subscript-result) [*代码块*](#code-block)
|
||||||
> *下标声明* → [*下标头*](#subscript-head) [*下标结果*](#subscript-result) [*getter-setter代码块*](#getter-setter-block)
|
> *下标声明* → [*下标头*](#subscript-head) [*下标结果*](#subscript-result) [*getter-setter 代码块*](#getter-setter-block)
|
||||||
> *下标声明* → [*下标头*](#subscript-head) [*下标结果*](#subscript-result) [*getter-setter关键字代码块*](#getter-setter-keyword-block)
|
> *下标声明* → [*下标头*](#subscript-head) [*下标结果*](#subscript-result) [*getter-setter 关键字代码块*](#getter-setter-keyword-block)
|
||||||
> <a name="subscript-head"></a>
|
> <a name="subscript-head"></a>
|
||||||
> *下标头* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> [*声明修饰符列表*](#declaration-modifiers)<sub>可选</sub> **subscript** [*参数子句*](#parameter-clause)
|
> *下标头* → [*特性列表*](06_Attributes.md#attributes)<sub>可选</sub> [*声明修饰符列表*](#declaration-modifiers)<sub>可选</sub> **subscript** [*参数子句*](#parameter-clause)
|
||||||
> <a name="subscript-result"></a>
|
> <a name="subscript-result"></a>
|
||||||
@ -1168,7 +1174,7 @@ infix operator 运算符名称: 优先级组
|
|||||||
|
|
||||||
中缀运算符是二元运算符,置于两个运算对象之间,例如加法运算符(`+`)位于表达式 `1 + 2` 的中间。
|
中缀运算符是二元运算符,置于两个运算对象之间,例如加法运算符(`+`)位于表达式 `1 + 2` 的中间。
|
||||||
|
|
||||||
中缀运算符可以选择指定优先级组。如果没有为运算符设置优先级组,Swift会设置默认优先级组`DefaultPrecedence`,它的优先级比三目优先级`TernaryPrecedence`要高,更多内容参考[*优先级组声明*](#precedence_group_declaration_modifiers)
|
中缀运算符可以选择指定优先级组。如果没有为运算符设置优先级组,Swift 会设置默认优先级组 `DefaultPrecedence`,它的优先级比三目优先级 `TernaryPrecedence` 要高,更多内容参考[*优先级组声明*](#precedence_group_declaration_modifiers)
|
||||||
|
|
||||||
下面的形式声明了一个新的前缀运算符:
|
下面的形式声明了一个新的前缀运算符:
|
||||||
|
|
||||||
@ -1223,16 +1229,18 @@ precedencegroup 优先级组名称{
|
|||||||
assignment: 赋值性
|
assignment: 赋值性
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
较低优先级组和较高优先级组的名称说明了新建的优先级组是依赖于现存的优先级组的。 `lowerThan`优先级组的属性只可以引用当前模块外的优先级组。当两个运算符为同一个操作数竞争时,比如表达式`2 + 3 * 5`,优先级更高的运算符将优先参与运算。
|
|
||||||
|
较低优先级组和较高优先级组的名称说明了新建的优先级组是依赖于现存的优先级组的。`lowerThan` 优先级组的属性只可以引用当前模块外的优先级组。当两个运算符为同一个操作数竞争时,比如表达式 `2 + 3 * 5`,优先级更高的运算符将优先参与运算。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
|
>
|
||||||
> 使用较低和较高优先级组相互联系的优先级组必须保持单一层次关系,但它们不必是线性关系。这意味着优先级组也许会有未定义的相关优先级。这些优先级组的运算符在没有用圆括号分组的情况下是不能紧邻着使用的。
|
> 使用较低和较高优先级组相互联系的优先级组必须保持单一层次关系,但它们不必是线性关系。这意味着优先级组也许会有未定义的相关优先级。这些优先级组的运算符在没有用圆括号分组的情况下是不能紧邻着使用的。
|
||||||
|
|
||||||
Swift定义了大量的优先级组来与标准库的运算符配合使用,例如相加(`+`)和相减(`-`)属于`AdditionPrecedence`组,相乘(`*`)和相除(`/`)属于` MultiplicationPrecedence`组,详细关于Swift标准库中一系列运算符和优先级组内容,参阅[Swift标准库操作符参考](https://developer.apple.com/reference/swift/1851035-swift_standard_library_operators)。
|
Swift 定义了大量的优先级组来与标准库的运算符配合使用,例如相加(`+`)和相减(`-`)属于 `AdditionPrecedence` 组,相乘(`*`)和相除(`/`)属于 `MultiplicationPrecedence` 组,详细关于 Swift 标准库中一系列运算符和优先级组内容,参阅[Swift 标准库操作符参考](https://developer.apple.com/reference/swift/1851035-swift_standard_library_operators)。
|
||||||
|
|
||||||
运算符的结合性表示在没有圆括号分组的情况下,同样优先级的一系列运算符是如何被分组的。你可以指定运算符的结合性通过上下文关键字`left`、`right`或者`none`,如果没有指定结合性,默认是`none`关键字。左关联性的运算符是从左至右分组的,例如,相减操作符(-)是左关联性的,所以表达式`4 - 5 - 6`被分组为`(4 - 5) - 6`,得出结果-7。右关联性的运算符是从右往左分组的,指定为`none`结合性的运算符就没有结合性。同样优先级没有结合性的运算符不能相邻出现,例如`<`运算符是`none`结合性,那表示`1 < 2 < 3`就不是一个有效表达式。
|
运算符的结合性表示在没有圆括号分组的情况下,同样优先级的一系列运算符是如何被分组的。你可以指定运算符的结合性通过上下文关键字 `left`、`right` 或者 `none`,如果没有指定结合性,默认是 `none` 关键字。左关联性的运算符是从左至右分组的,例如,相减操作符(-)是左关联性的,所以表达式 `4 - 5 - 6` 被分组为 `(4 - 5) - 6`,得出结果-7。右关联性的运算符是从右往左分组的,指定为 `none` 结合性的运算符就没有结合性。同样优先级没有结合性的运算符不能相邻出现,例如 `<` 运算符是 `none` 结合性,那表示 `1 < 2 < 3` 就不是一个有效表达式。
|
||||||
|
|
||||||
优先级组的赋值性表示在包含可选链操作时的运算符优先级。当设为true时,与优先级组对应的运算符在可选链操作中使用和标准库中赋值运算符同样的分组规则,当设为false或者不设置,该优先级组的运算符与不赋值的运算符遵循同样的可选链规则。
|
优先级组的赋值性表示在包含可选链操作时的运算符优先级。当设为 true 时,与优先级组对应的运算符在可选链操作中使用和标准库中赋值运算符同样的分组规则,当设为 false 或者不设置,该优先级组的运算符与不赋值的运算符遵循同样的可选链规则。
|
||||||
|
|
||||||
<a name="grammer_of_a_precedence_group_declaration"></a>
|
<a name="grammer_of_a_precedence_group_declaration"></a>
|
||||||
> 优先级组声明语法
|
> 优先级组声明语法
|
||||||
@ -1320,6 +1328,6 @@ Swift 提供了三个级别的访问控制:`public`、`internal` 和 `private`
|
|||||||
> *声明修饰符列表* → [*声明修饰符*](#declaration-modifier) [*声明修饰符列表*](#declaration-modifiers)<sub>可选</sub>
|
> *声明修饰符列表* → [*声明修饰符*](#declaration-modifier) [*声明修饰符列表*](#declaration-modifiers)<sub>可选</sub>
|
||||||
|
|
||||||
<a name="access-level-modifier"></a>
|
<a name="access-level-modifier"></a>
|
||||||
>访问级别修饰符 → **internal** | **internal ( set )**
|
> 访问级别修饰符 → **internal** | **internal ( set )**
|
||||||
>访问级别修饰符 → **private** | **private ( set )**
|
> 访问级别修饰符 → **private** | **private ( set )**
|
||||||
>访问级别修饰符 → **public** | **public ( set )**
|
> 访问级别修饰符 → **public** | **public ( set )**
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
> 翻译+校对:[KYawn](https://github.com/KYawn)
|
> 翻译+校对:[KYawn](https://github.com/KYawn)
|
||||||
|
|
||||||
> 2.1
|
> 2.1
|
||||||
> 翻译:[小铁匠Linus](https://github.com/kevin833752)
|
> 翻译:[小铁匠 Linus](https://github.com/kevin833752)
|
||||||
|
|
||||||
本页内容包括:
|
本页内容包括:
|
||||||
|
|
||||||
@ -17,9 +17,9 @@
|
|||||||
- [Interface Builder 使用的声明特性](#declaration_attributes_used_by_interface_builder)
|
- [Interface Builder 使用的声明特性](#declaration_attributes_used_by_interface_builder)
|
||||||
- [类型特性](#type_attributes)
|
- [类型特性](#type_attributes)
|
||||||
|
|
||||||
特性提供了有关声明和类型的更多信息。在Swift中有两种特性,分别用于修饰声明和类型。
|
特性提供了有关声明和类型的更多信息。在 Swift 中有两种特性,分别用于修饰声明和类型。
|
||||||
|
|
||||||
您可以通过以下方式指定一个特性:符号`@`后跟特性的名称和特性接收的任何参数:
|
您可以通过以下方式指定一个特性:符号 `@` 后跟特性的名称和特性接收的任何参数:
|
||||||
|
|
||||||
> @ `特性名`
|
> @ `特性名`
|
||||||
|
|
||||||
@ -50,38 +50,38 @@
|
|||||||
当然,你也可以用一个星号(*)来表示上面提到的所有平台。
|
当然,你也可以用一个星号(*)来表示上面提到的所有平台。
|
||||||
其余的参数,可以按照任何顺序出现,并且可以添加关于声明生命周期的附加信息,包括重要事件。
|
其余的参数,可以按照任何顺序出现,并且可以添加关于声明生命周期的附加信息,包括重要事件。
|
||||||
|
|
||||||
- `unavailable`参数表示该声明在指定的平台上是无效的。
|
- `unavailable` 参数表示该声明在指定的平台上是无效的。
|
||||||
- `introduced` 参数表示指定平台从哪一版本开始引入该声明。格式如下:
|
- `introduced` 参数表示指定平台从哪一版本开始引入该声明。格式如下:
|
||||||
|
|
||||||
`introduced`=`版本号`
|
`introduced`=` 版本号 `
|
||||||
|
|
||||||
*版本号*由一个或多个正整数构成,由句点分隔的。
|
*版本号*由一个或多个正整数构成,由句点分隔的。
|
||||||
|
|
||||||
- `deprecated`参数表示指定平台从哪一版本开始弃用该声明。格式如下:
|
- `deprecated` 参数表示指定平台从哪一版本开始弃用该声明。格式如下:
|
||||||
|
|
||||||
`deprecated`=`版本号`
|
`deprecated`=` 版本号 `
|
||||||
|
|
||||||
可选的*版本号*由一个或多个正整数构成,由句点分隔的。省略版本号表示该声明目前已弃用,当弃用出现时无需给出任何有关信息。如果你省略了版本号,冒号(:)也可省略。
|
可选的*版本号*由一个或多个正整数构成,由句点分隔的。省略版本号表示该声明目前已弃用,当弃用出现时无需给出任何有关信息。如果你省略了版本号,冒号(:)也可省略。
|
||||||
|
|
||||||
- `obsoleted` 参数表示指定平台从哪一版本开始废弃该声明。当一个声明被废弃后,它就从平台中移除,不能再被使用。格式如下:
|
- `obsoleted` 参数表示指定平台从哪一版本开始废弃该声明。当一个声明被废弃后,它就从平台中移除,不能再被使用。格式如下:
|
||||||
|
|
||||||
`obsoleted`=`版本号`
|
`obsoleted`=` 版本号 `
|
||||||
|
|
||||||
*版本号*由一个或多个正整数构成,由句点分隔的。
|
*版本号*由一个或多个正整数构成,由句点分隔的。
|
||||||
|
|
||||||
- `message` 参数用来提供文本信息。当使用被弃用或者被废弃的声明时,编译器会抛出警告或错误信息。格式如下:
|
- `message` 参数用来提供文本信息。当使用被弃用或者被废弃的声明时,编译器会抛出警告或错误信息。格式如下:
|
||||||
|
|
||||||
`message`=`信息内容`
|
`message`=` 信息内容 `
|
||||||
|
|
||||||
信息内容由一个字符串构成。
|
信息内容由一个字符串构成。
|
||||||
|
|
||||||
- `renamed` 参数用来提供文本信息,用以表示被重命名的声明的新名字。当使用声明的旧名字时,编译器会报错提示新名字。格式如下:
|
- `renamed` 参数用来提供文本信息,用以表示被重命名的声明的新名字。当使用声明的旧名字时,编译器会报错提示新名字。格式如下:
|
||||||
|
|
||||||
`renamed`=`新名字`
|
`renamed`=` 新名字 `
|
||||||
|
|
||||||
新名字由一个字符串构成。
|
新名字由一个字符串构成。
|
||||||
|
|
||||||
你可以将`renamed` 参数和 `unavailable` 参数以及类型别名声明组合使用,以此向用户表示某个声明已经被重命名。当某个声明的名字在一个框架或者库的不同发布版本间发生变化时,这会相当有用。
|
你可以将 `renamed` 参数和 `unavailable` 参数以及类型别名声明组合使用,以此向用户表示某个声明已经被重命名。当某个声明的名字在一个框架或者库的不同发布版本间发生变化时,这会相当有用。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
// 首发版本
|
// 首发版本
|
||||||
@ -120,7 +120,7 @@ class MyClass {
|
|||||||
|
|
||||||
`GKInspectable`
|
`GKInspectable`
|
||||||
|
|
||||||
应用此属性,暴露一个自定义GameplayKit组件属性给SpriteKit编辑器UI。
|
应用此属性,暴露一个自定义 GameplayKit 组件属性给 SpriteKit 编辑器 UI。
|
||||||
|
|
||||||
`objc`
|
`objc`
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ var enabled: Bool {
|
|||||||
|
|
||||||
在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `NSApplicationMain`(\_:_:) 函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
|
在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `NSApplicationMain`(\_:_:) 函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
|
||||||
|
|
||||||
如果你不想使用这个特性,可以提供一个 main.swift 文件,并在代码**顶层**调用`NSApplicationMain`(\_:_:) 函数,如下所示:
|
如果你不想使用这个特性,可以提供一个 main.swift 文件,并在代码**顶层**调用 `NSApplicationMain`(\_:_:) 函数,如下所示:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
import AppKit
|
import AppKit
|
||||||
@ -167,26 +167,26 @@ NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
|
|||||||
|
|
||||||
`NSManaged`
|
`NSManaged`
|
||||||
|
|
||||||
该特性用于修饰 `NSManagedObject` 子类中的实例方法或存储型变量属性,表明它们的实现由 `Core Data` 在运行时基于相关实体描述动态提供。对于标记了 `NSManaged` 特性的属性,`Core Data` 也会在运行时为其提供存储。应用这个特性也意味着`objc`特性。
|
该特性用于修饰 `NSManagedObject` 子类中的实例方法或存储型变量属性,表明它们的实现由 `Core Data` 在运行时基于相关实体描述动态提供。对于标记了 `NSManaged` 特性的属性,`Core Data` 也会在运行时为其提供存储。应用这个特性也意味着 `objc` 特性。
|
||||||
|
|
||||||
`testable`
|
`testable`
|
||||||
|
|
||||||
在导入允许测试的编译模块时,该特性用于修饰 `import` 声明,这样就能访问被导入模块中的任何标有 `internal` 访问级别修饰符的实体,犹如它们被标记了 `public` 访问级别修饰符。测试也可以访问使用`internal`或者`public`访问级别修饰符标记的类和类成员,就像它们是`open`访问修饰符声明的。
|
在导入允许测试的编译模块时,该特性用于修饰 `import` 声明,这样就能访问被导入模块中的任何标有 `internal` 访问级别修饰符的实体,犹如它们被标记了 `public` 访问级别修饰符。测试也可以访问使用 `internal` 或者 `public` 访问级别修饰符标记的类和类成员,就像它们是 `open` 访问修饰符声明的。
|
||||||
|
|
||||||
`UIApplicationMain`
|
`UIApplicationMain`
|
||||||
|
|
||||||
在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `UIApplicationMain`函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
|
在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `UIApplicationMain` 函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
|
||||||
|
|
||||||
如果你不想使用这个特性,可以提供一个 main.swift 文件,并在代码顶层调用 `UIApplicationMain`(\_:\_:\_:) 函数。比如,如果你的应用程序使用一个继承于 UIApplication 的自定义子类作为主要类,你可以调用 `UIApplicationMain`(\_:\_:\_:) 函数而不是使用该特性。
|
如果你不想使用这个特性,可以提供一个 main.swift 文件,并在代码顶层调用 `UIApplicationMain`(\_:\_:\_:) 函数。比如,如果你的应用程序使用一个继承于 UIApplication 的自定义子类作为主要类,你可以调用 `UIApplicationMain`(\_:\_:\_:) 函数而不是使用该特性。
|
||||||
|
|
||||||
<a name="declaration_attributes_used_by_interface_builder"></a>
|
<a name="declaration_attributes_used_by_interface_builder"></a>
|
||||||
###Interface Builder 使用的声明特性
|
###Interface Builder 使用的声明特性
|
||||||
|
|
||||||
`Interface Builder` 特性是 `Interface Builder` 用来与 Xcode 同步的声明特性。`Swift` 提供了以下的 `Interface Builder` 特性:`IBAction`,`IBOutlet`,`IBDesignable`,以及`IBInspectable` 。这些特性与 Objective-C 中对应的特性在概念上是相同的。
|
`Interface Builder` 特性是 `Interface Builder` 用来与 Xcode 同步的声明特性。`Swift` 提供了以下的 `Interface Builder` 特性:`IBAction`,`IBOutlet`,`IBDesignable`,以及 `IBInspectable` 。这些特性与 Objective-C 中对应的特性在概念上是相同的。
|
||||||
|
|
||||||
`IBOutlet` 和 `IBInspectable` 用于修饰一个类的属性声明,`IBAction` 特性用于修饰一个类的方法声明,`IBDesignable` 用于修饰类的声明。
|
`IBOutlet` 和 `IBInspectable` 用于修饰一个类的属性声明,`IBAction` 特性用于修饰一个类的方法声明,`IBDesignable` 用于修饰类的声明。
|
||||||
|
|
||||||
`IBAction` 和 `IBOutlet` 特性都意味着`objc`特性。
|
`IBAction` 和 `IBOutlet` 特性都意味着 `objc` 特性。
|
||||||
|
|
||||||
<a name="type_attributes"></a>
|
<a name="type_attributes"></a>
|
||||||
##类型特性
|
##类型特性
|
||||||
@ -213,7 +213,7 @@ convention 特性总是与下面的参数之一一起出现。
|
|||||||
`escaping`
|
`escaping`
|
||||||
在函数或者方法声明上使用该特性,它表示参数将不会被存储以供延迟执行,这将确保参数不会超出函数调用的生命周期。在使用 `escaping` 声明特性的函数类型中访问属性和方法时不需要显式地使用 `self.`。关于如何使用 `escaping` 特性的例子,请参阅 [逃逸闭包](http://wiki.jikexueyuan.com/project/swift/chapter2/07_Closures.html)。
|
在函数或者方法声明上使用该特性,它表示参数将不会被存储以供延迟执行,这将确保参数不会超出函数调用的生命周期。在使用 `escaping` 声明特性的函数类型中访问属性和方法时不需要显式地使用 `self.`。关于如何使用 `escaping` 特性的例子,请参阅 [逃逸闭包](http://wiki.jikexueyuan.com/project/swift/chapter2/07_Closures.html)。
|
||||||
|
|
||||||
>特性语法
|
> 特性语法
|
||||||
|
|
||||||
> *特性 *→ @ <font color = 0x3386c8>特性名 特性参数子句</font><sub>可选</sub>
|
> *特性 *→ @ <font color = 0x3386c8>特性名 特性参数子句</font><sub>可选</sub>
|
||||||
|
|
||||||
|
|||||||
@ -193,11 +193,11 @@ for case let number? in arrayOfOptinalInts {
|
|||||||
|
|
||||||
> 类型转换模式语法
|
> 类型转换模式语法
|
||||||
<a name="type-casting-pattern"></a>
|
<a name="type-casting-pattern"></a>
|
||||||
> *类型转换模式* → [*is模式*](#is-pattern) | [*as模式*](#as-pattern)
|
> *类型转换模式* → [*is 模式*](#is-pattern) | [*as 模式*](#as-pattern)
|
||||||
<a name="is-pattern"></a>
|
<a name="is-pattern"></a>
|
||||||
> *is模式* → **is** [*类型*](03_Types.md#type)
|
> *is 模式* → **is** [*类型*](03_Types.md#type)
|
||||||
<a name="as-pattern"></a>
|
<a name="as-pattern"></a>
|
||||||
> *as模式* → [*模式*](#pattern) **as** [*类型*](03_Types.md#type)
|
> *as 模式* → [*模式*](#pattern) **as** [*类型*](03_Types.md#type)
|
||||||
|
|
||||||
<a name="expression_pattern"></a>
|
<a name="expression_pattern"></a>
|
||||||
## 表达式模式(Expression Pattern)
|
## 表达式模式(Expression Pattern)
|
||||||
|
|||||||
@ -45,7 +45,7 @@ func simpleMax<T: Comparable>(_ x: T, _ y: T) -> T {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
例如,因为 `Int` 和 `Double` 均满足`Comparable`协议,所以该函数可以接受这两种类型。与泛型类型相反,调用泛型函数或构造器时不需要指定泛型实参子句。类型实参由传递给函数或构造器的实参推断而出。
|
例如,因为 `Int` 和 `Double` 均满足 `Comparable` 协议,所以该函数可以接受这两种类型。与泛型类型相反,调用泛型函数或构造器时不需要指定泛型实参子句。类型实参由传递给函数或构造器的实参推断而出。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
simpleMax(17, 42) // T 被推断为 Int 类型
|
simpleMax(17, 42) // T 被推断为 Int 类型
|
||||||
@ -59,15 +59,15 @@ simpleMax(3.14159, 2.71828) // T 被推断为 Double 类型
|
|||||||
|
|
||||||
> `where` : `类型要求`
|
> `where` : `类型要求`
|
||||||
|
|
||||||
`where` 子句中的要求用于指明该类型形参继承自某个类或符合某个协议或协议组合。尽管 `where` 子句提供了语法糖使其有助于表达类型形参上的简单约束(如 `<T: Comparable>` 等同于 `<T> where T: Comparable`,等等),但是依然可以用来对类型形参及其关联类型提供更复杂的约束,例如你可以强制形参的关联类型遵守协议,如,` <S: Sequence> where S.Iterator.Element: Equatable` 表示泛型类型 `S` 遵守`Sequence`协议并且关联类型`S.Iterator.Element`遵守`Equatable`协议,这个约束确保队列的每一个元素都是符合 `Equatable` 协议的。
|
`where` 子句中的要求用于指明该类型形参继承自某个类或符合某个协议或协议组合。尽管 `where` 子句提供了语法糖使其有助于表达类型形参上的简单约束(如 `<T: Comparable>` 等同于 `<T> where T: Comparable`,等等),但是依然可以用来对类型形参及其关联类型提供更复杂的约束,例如你可以强制形参的关联类型遵守协议,如,`<S: Sequence> where S.Iterator.Element: Equatable` 表示泛型类型 `S` 遵守 `Sequence` 协议并且关联类型 `S.Iterator.Element` 遵守 `Equatable` 协议,这个约束确保队列的每一个元素都是符合 `Equatable` 协议的。
|
||||||
|
|
||||||
也可以用操作符 `==` 来指定两个类型必须相同。例如,泛型形参子句 ` <S1: Sequence, S2: Sequence> where S1.Iterator.Element == S2.Iterator.Element` 表示 `S1` 和 `S2` 必须都符合 `SequenceType` 协议,而且两个序列中的元素类型必须相同。
|
也可以用操作符 `==` 来指定两个类型必须相同。例如,泛型形参子句 `<S1: Sequence, S2: Sequence> where S1.Iterator.Element == S2.Iterator.Element` 表示 `S1` 和 `S2` 必须都符合 `SequenceType` 协议,而且两个序列中的元素类型必须相同。
|
||||||
|
|
||||||
当然,替代类型形参的类型实参必须满足所有的约束和要求。
|
当然,替代类型形参的类型实参必须满足所有的约束和要求。
|
||||||
|
|
||||||
泛型函数或构造器可以重载,但在泛型形参子句中的类型形参必须有不同的约束或要求,抑或二者皆不同。当调用重载的泛型函数或构造器时,编译器会根据这些约束来决定调用哪个重载函数或构造器。
|
泛型函数或构造器可以重载,但在泛型形参子句中的类型形参必须有不同的约束或要求,抑或二者皆不同。当调用重载的泛型函数或构造器时,编译器会根据这些约束来决定调用哪个重载函数或构造器。
|
||||||
|
|
||||||
更多关于泛型where从句的信息和关于泛型函数声明的例子,可以看一看 [泛型where子句](https://github.com/numbbbbb/the-swift-programming-language-in-chinese/blob/gh-pages/source/chapter2/23_Generics.md#where_clauses)
|
更多关于泛型 where 从句的信息和关于泛型函数声明的例子,可以看一看 [泛型 where 子句](https://github.com/numbbbbb/the-swift-programming-language-in-chinese/blob/gh-pages/source/chapter2/23_Generics.md#where_clauses)
|
||||||
|
|
||||||
> 泛型形参子句语法
|
> 泛型形参子句语法
|
||||||
|
|
||||||
|
|||||||
@ -38,32 +38,32 @@
|
|||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> 循环语句语法
|
> 循环语句语法
|
||||||
> *循环语句* → [*for语句*](../chapter3/10_Statements.html#for_statement)
|
> *循环语句* → [*for 语句*](../chapter3/10_Statements.html#for_statement)
|
||||||
> *循环语句* → [*for-in语句*](../chapter3/10_Statements.html#for_in_statement)
|
> *循环语句* → [*for-in 语句*](../chapter3/10_Statements.html#for_in_statement)
|
||||||
> *循环语句* → [*while语句*](../chapter3/10_Statements.html#wheetatype类型ile_statement)
|
> *循环语句* → [*while 语句*](../chapter3/10_Statements.html#wheetatype 类型 ile_statement)
|
||||||
> *循环语句* → [*repeat-while语句*](../chapter3/10_Statements.html#do_while_statement)
|
> *循环语句* → [*repeat-while 语句*](../chapter3/10_Statements.html#do_while_statement)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> For 循环语法
|
> For 循环语法
|
||||||
> *for语句* → **for** [*for初始条件*](../chapter3/10_Statements.html#for_init) _可选_ **;** [*表达式*](../chapter3/04_Expressions.html#expression) _可选_ **;** [*表达式*](../chapter3/04_Expressions.html#expression) _可选_ [*代码块*](../chapter3/05_Declarations.html#code_block)
|
> *for 语句* → **for** [*for 初始条件*](../chapter3/10_Statements.html#for_init) _可选_ **;** [*表达式*](../chapter3/04_Expressions.html#expression) _可选_ **;** [*表达式*](../chapter3/04_Expressions.html#expression) _可选_ [*代码块*](../chapter3/05_Declarations.html#code_block)
|
||||||
> *for语句* → **for** **(** [*for初始条件*](../chapter3/10_Statements.html#for_init) _可选_ **;** [*表达式*](../chapter3/04_Expressions.html#expression) _可选_ **;** [*表达式*](../chapter3/04_Expressions.html#expression) _可选_ **)** [*代码块*](../chapter3/05_Declarations.html#code_block)
|
> *for 语句* → **for** **(** [*for 初始条件*](../chapter3/10_Statements.html#for_init) _可选_ **;** [*表达式*](../chapter3/04_Expressions.html#expression) _可选_ **;** [*表达式*](../chapter3/04_Expressions.html#expression) _可选_ **)** [*代码块*](../chapter3/05_Declarations.html#code_block)
|
||||||
> *for初始条件* → [*变量声明*](../chapter3/05_Declarations.html#variable_declaration) | [*表达式集*](../chapter3/04_Expressions.html#expression_list)
|
> *for 初始条件* → [*变量声明*](../chapter3/05_Declarations.html#variable_declaration) | [*表达式集*](../chapter3/04_Expressions.html#expression_list)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> For-In 循环语法
|
> For-In 循环语法
|
||||||
> *for-in语句* → **for case** _可选_ [*模式*](../chapter3/07_Patterns.html#pattern) **in** [*表达式*](../chapter3/04_Expressions.html#expression) [*代码块*](../chapter3/05_Declarations.html#code_block) [*where从句*](TODO) _可选_
|
> *for-in 语句* → **for case** _可选_ [*模式*](../chapter3/07_Patterns.html#pattern) **in** [*表达式*](../chapter3/04_Expressions.html#expression) [*代码块*](../chapter3/05_Declarations.html#code_block) [*where 从句*](TODO) _可选_
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> While 循环语法
|
> While 循环语法
|
||||||
> *while语句* → **while** [*条件从句*](../chapter3/10_Statements.html#while_condition) [*代码块*](../chapter3/05_Declarations.html#code_block)
|
> *while 语句* → **while** [*条件从句*](../chapter3/10_Statements.html#while_condition) [*代码块*](../chapter3/05_Declarations.html#code_block)
|
||||||
> *条件从句* → [*表达式*](TODO)
|
> *条件从句* → [*表达式*](TODO)
|
||||||
|
|
||||||
> *条件从句* → [*表达式*](TODO) *,* [*表达式集*]()
|
> *条件从句* → [*表达式*](TODO) *,* [*表达式集*]()
|
||||||
|
|
||||||
>*条件从句* → [*表达式集*](TODO)
|
> *条件从句* → [*表达式集*](TODO)
|
||||||
|
|
||||||
> *条件从句* → [*可用条件 (availability-condition*)](TODO) *|* [*表达式集*]()
|
> *条件从句* → [*可用条件 (availability-condition*)](TODO) *|* [*表达式集*]()
|
||||||
|
|
||||||
@ -71,9 +71,9 @@
|
|||||||
|
|
||||||
> *条件* → [*可用条件(availability-condition)*](TODO) *|* [*个例条件(case-condition)*](TODO) *|* [*可选绑定条件(optional-binding-condition)*](TODO)
|
> *条件* → [*可用条件(availability-condition)*](TODO) *|* [*个例条件(case-condition)*](TODO) *|* [*可选绑定条件(optional-binding-condition)*](TODO)
|
||||||
|
|
||||||
> *个例条件(case-condition)* → **case** [*模式*](TODO) [*构造器*](TODO) [*where从句*](TODO)_可选_
|
> *个例条件(case-condition)* → **case** [*模式*](TODO) [*构造器*](TODO) [*where 从句*](TODO)_可选_
|
||||||
|
|
||||||
> *可选绑定条件(optional-binding-condition)* → [*可选绑定头(optional-binding-head)*](TODO) [*可选绑定连续集(optional-binding-continuation-list)*](TODO) _可选_ [*where从句*](TODO) _可选_
|
> *可选绑定条件(optional-binding-condition)* → [*可选绑定头(optional-binding-head)*](TODO) [*可选绑定连续集(optional-binding-continuation-list)*](TODO) _可选_ [*where 从句*](TODO) _可选_
|
||||||
|
|
||||||
> *可选绑定头(optional-binding-head)* → **let** [*模式 构造器*](TODO) *|* **var** [*模式 构造器*](TODO)
|
> *可选绑定头(optional-binding-head)* → **let** [*模式 构造器*](TODO) *|* **var** [*模式 构造器*](TODO)
|
||||||
|
|
||||||
@ -82,120 +82,120 @@
|
|||||||
> *可选绑定连续(optional-binding-continuation)* → [*模式 构造器*](TODO) *|* [*可选绑定头(optional-binding-head)*](TODO)
|
> *可选绑定连续(optional-binding-continuation)* → [*模式 构造器*](TODO) *|* [*可选绑定头(optional-binding-head)*](TODO)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
> Repeat-While语句语法
|
> Repeat-While 语句语法
|
||||||
*repeat-while-statement* → **repeat** [*代码块*](TODO) **while** [*表达式*](TODO)
|
*repeat-while-statement* → **repeat** [*代码块*](TODO) **while** [*表达式*](TODO)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> 分支语句语法
|
> 分支语句语法
|
||||||
> *分支语句* → [*if语句*](../chapter3/10_Statements.html#if_statement)
|
> *分支语句* → [*if 语句*](../chapter3/10_Statements.html#if_statement)
|
||||||
|
|
||||||
> *分支语句* → [*guard语句*](TODO)
|
> *分支语句* → [*guard 语句*](TODO)
|
||||||
|
|
||||||
> *分支语句* → [*switch语句*](../chapter3/10_Statements.html#switch_statement)
|
> *分支语句* → [*switch 语句*](../chapter3/10_Statements.html#switch_statement)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> If语句语法
|
> If 语句语法
|
||||||
> *if语句* → **if** [*条件从句*](TODO) [*代码块*](TODO) [*else从句(Clause)*](TODO) _可选_
|
> *if 语句* → **if** [*条件从句*](TODO) [*代码块*](TODO) [*else 从句(Clause)*](TODO) _可选_
|
||||||
|
|
||||||
> *else从句(Clause)* → **else** [*代码块*](../chapter3/05_Declarations.html#code_block) | **else** [*if语句*](../chapter3/10_Statements.html#if_statement)
|
> *else 从句(Clause)* → **else** [*代码块*](../chapter3/05_Declarations.html#code_block) | **else** [*if 语句*](../chapter3/10_Statements.html#if_statement)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
>Guard 语句语法
|
> Guard 语句语法
|
||||||
>*guard语句* → **guard** [*条件从句*](TODO) **else** [*代码块*](TODO)
|
> *guard 语句* → **guard** [*条件从句*](TODO) **else** [*代码块*](TODO)
|
||||||
|
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> Switch语句语法
|
> Switch 语句语法
|
||||||
> *switch语句* → **switch** [*表达式*](../chapter3/04_Expressions.html#expression) **{** [*SwitchCase*](../chapter3/10_Statements.html#switch_cases) _可选_ **}**
|
> *switch 语句* → **switch** [*表达式*](../chapter3/04_Expressions.html#expression) **{** [*SwitchCase*](../chapter3/10_Statements.html#switch_cases) _可选_ **}**
|
||||||
> *SwitchCase集* → [*SwitchCase*](../chapter3/10_Statements.html#switch_case) [*SwitchCase集*](../chapter3/10_Statements.html#switch_cases) _可选_
|
> *SwitchCase 集* → [*SwitchCase*](../chapter3/10_Statements.html#switch_case) [*SwitchCase 集*](../chapter3/10_Statements.html#switch_cases) _可选_
|
||||||
> *SwitchCase* → [*case标签*](../chapter3/10_Statements.html#case_label) [*多条语句(Statements)*](../chapter3/10_Statements.html#statements) | [*default标签*](../chapter3/10_Statements.html#default_label) [*多条语句(Statements)*](../chapter3/10_Statements.html#statements)
|
> *SwitchCase* → [*case 标签*](../chapter3/10_Statements.html#case_label) [*多条语句(Statements)*](../chapter3/10_Statements.html#statements) | [*default 标签*](../chapter3/10_Statements.html#default_label) [*多条语句(Statements)*](../chapter3/10_Statements.html#statements)
|
||||||
> *SwitchCase* → [*case标签*](../chapter3/10_Statements.html#case_label) **;** | [*default标签*](../chapter3/10_Statements.html#default_label) **;**
|
> *SwitchCase* → [*case 标签*](../chapter3/10_Statements.html#case_label) **;** | [*default 标签*](../chapter3/10_Statements.html#default_label) **;**
|
||||||
> *case标签* → **case** [*case项集*](../chapter3/10_Statements.html#case_item_list) **:**
|
> *case 标签* → **case** [*case 项集*](../chapter3/10_Statements.html#case_item_list) **:**
|
||||||
> *case项集* → [*模式*](../chapter3/07_Patterns.html#pattern) [*where-clause*](../chapter3/10_Statements.html#guard_clause) _可选_ | [*模式*](../chapter3/07_Patterns.html#pattern) [*where-clause*](../chapter3/10_Statements.html#guard_clause) _可选_ **,** [*case项集*](../chapter3/10_Statements.html#case_item_list)
|
> *case 项集* → [*模式*](../chapter3/07_Patterns.html#pattern) [*where-clause*](../chapter3/10_Statements.html#guard_clause) _可选_ | [*模式*](../chapter3/07_Patterns.html#pattern) [*where-clause*](../chapter3/10_Statements.html#guard_clause) _可选_ **,** [*case 项集*](../chapter3/10_Statements.html#case_item_list)
|
||||||
> *default标签* → **default** **:**
|
> *default 标签* → **default** **:**
|
||||||
> *where从句* → **where** [*where表达式*](TODO)
|
> *where 从句* → **where** [*where 表达式*](TODO)
|
||||||
> *where表达式* → [*表达式*](TODO)
|
> *where 表达式* → [*表达式*](TODO)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> 标记语句语法
|
> 标记语句语法
|
||||||
> *标记语句(Labeled Statement)* → [*语句标签*](../chapter3/10_Statements.html#statement_label) [*循环语句*](../chapter3/10_Statements.html#loop_statement) | [*语句标签*](../chapter3/10_Statements.html#statement_label) [*if语句*](../chapter3/10_Statements.html#switch_statement) | [*语句标签*](TODY) [*switch语句*](TODY)
|
> *标记语句(Labeled Statement)* → [*语句标签*](../chapter3/10_Statements.html#statement_label) [*循环语句*](../chapter3/10_Statements.html#loop_statement) | [*语句标签*](../chapter3/10_Statements.html#statement_label) [*if 语句*](../chapter3/10_Statements.html#switch_statement) | [*语句标签*](TODY) [*switch 语句*](TODY)
|
||||||
> *语句标签* → [*标签名称*](../chapter3/10_Statements.html#label_name) **:**
|
> *语句标签* → [*标签名称*](../chapter3/10_Statements.html#label_name) **:**
|
||||||
> *标签名称* → [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
> *标签名称* → [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> 控制传递语句(Control Transfer Statement) 语法
|
> 控制传递语句(Control Transfer Statement) 语法
|
||||||
> *控制传递语句* → [*break语句*](../chapter3/10_Statements.html#break_statement)
|
> *控制传递语句* → [*break 语句*](../chapter3/10_Statements.html#break_statement)
|
||||||
> *控制传递语句* → [*continue语句*](../chapter3/10_Statements.html#continue_statement)
|
> *控制传递语句* → [*continue 语句*](../chapter3/10_Statements.html#continue_statement)
|
||||||
> *控制传递语句* → [*fallthrough语句*](../chapter3/10_Statements.html#fallthrough_statement)
|
> *控制传递语句* → [*fallthrough 语句*](../chapter3/10_Statements.html#fallthrough_statement)
|
||||||
> *控制传递语句* → [*return语句*](../chapter3/10_Statements.html#return_statement)
|
> *控制传递语句* → [*return 语句*](../chapter3/10_Statements.html#return_statement)
|
||||||
> *控制传递语句* → [*throw语句*](TODO)
|
> *控制传递语句* → [*throw 语句*](TODO)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> Break 语句语法
|
> Break 语句语法
|
||||||
> *break语句* → **break** [*标签名称*](../chapter3/10_Statements.html#label_name) _可选_
|
> *break 语句* → **break** [*标签名称*](../chapter3/10_Statements.html#label_name) _可选_
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> Continue 语句语法
|
> Continue 语句语法
|
||||||
> *continue语句* → **continue** [*标签名称*](../chapter3/10_Statements.html#label_name) _可选_
|
> *continue 语句* → **continue** [*标签名称*](../chapter3/10_Statements.html#label_name) _可选_
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> Fallthrough 语句语法
|
> Fallthrough 语句语法
|
||||||
> *fallthrough语句* → **fallthrough**
|
> *fallthrough 语句* → **fallthrough**
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> Return 语句语法
|
> Return 语句语法
|
||||||
> *return语句* → **return** [*表达式*](../chapter3/04_Expressions.html#expression) _可选_
|
> *return 语句* → **return** [*表达式*](../chapter3/04_Expressions.html#expression) _可选_
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
>可用条件(Availability Condition)语法
|
> 可用条件(Availability Condition)语法
|
||||||
|
|
||||||
>*可用条件(availability-condition)* → **#available** **(** [*多可用参数*(availability-arguments)](TODO) **)**
|
> *可用条件(availability-condition)* → **#available** **(** [*多可用参数*(availability-arguments)](TODO) **)**
|
||||||
|
|
||||||
>*多可用参数(availability- arguments)* → [*可用参数(availability-argument)*](TODO)|[*可用参数(availability-argument)*](TODO) , [多可用参数(availability-arguments)](TODO)
|
> *多可用参数(availability- arguments)* → [*可用参数(availability-argument)*](TODO)|[*可用参数(availability-argument)*](TODO) , [多可用参数(availability-arguments)](TODO)
|
||||||
|
|
||||||
>*可用参数(availability- argument)* → [*平台名(platform-name)*](TODO) [*平台版本(platform-version)*](TODO)
|
> *可用参数(availability- argument)* → [*平台名(platform-name)*](TODO) [*平台版本(platform-version)*](TODO)
|
||||||
|
|
||||||
>*可用参数(availability- argument)* → *
|
> *可用参数(availability- argument)* → *
|
||||||
|
|
||||||
>*平台名* → **iOS** | **iOSApplicationExtension**
|
> *平台名* → **iOS** | **iOSApplicationExtension**
|
||||||
|
|
||||||
>*平台名* → **OSX** | **OSXApplicationExtension**
|
> *平台名* → **OSX** | **OSXApplicationExtension**
|
||||||
|
|
||||||
>*平台名* → **watchOS**
|
> *平台名* → **watchOS**
|
||||||
|
|
||||||
>*平台版本* → [*十进制数(decimal-digits)*](TODO)
|
> *平台版本* → [*十进制数(decimal-digits)*](TODO)
|
||||||
|
|
||||||
>*平台版本* → [*十进制数(decimal-digits)*](TODO) . [*十进制数(decimal-digits)*](TODO)
|
> *平台版本* → [*十进制数(decimal-digits)*](TODO) . [*十进制数(decimal-digits)*](TODO)
|
||||||
|
|
||||||
>*平台版本* → [*十进制数(decimal-digits)*](TODO) **.** [*十进制数(decimal-digits)*](TODO) **.** [*十进制数(decimal-digits)*](TODO))
|
> *平台版本* → [*十进制数(decimal-digits)*](TODO) **.** [*十进制数(decimal-digits)*](TODO) **.** [*十进制数(decimal-digits)*](TODO))
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
>抛出语句(Throw Statement)语法
|
> 抛出语句(Throw Statement)语法
|
||||||
|
|
||||||
>*抛出语句(throw-statement)* → **throw** [*表达式(expression)*](TODO)
|
> *抛出语句(throw-statement)* → **throw** [*表达式(expression)*](TODO)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
>延迟语句 (defer-statement)语法
|
> 延迟语句 (defer-statement)语法
|
||||||
|
|
||||||
>*延迟语句(defer-statement)* → **defer** [*代码块*](TODO)
|
> *延迟语句(defer-statement)* → **defer** [*代码块*](TODO)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
>执行语句(do-statement)语法
|
> 执行语句(do-statement)语法
|
||||||
|
|
||||||
>*执行语句(do-statement)* → **do** [*代码块*](TODO) [*catch-clauses*](TODO) _可选_
|
> *执行语句(do-statement)* → **do** [*代码块*](TODO) [*catch-clauses*](TODO) _可选_
|
||||||
|
|
||||||
>*catch-clauses* → [*catch-clause*](TODO) [*catch-clauses*](TODO) _可选_
|
> *catch-clauses* → [*catch-clause*](TODO) [*catch-clauses*](TODO) _可选_
|
||||||
|
|
||||||
>*catch-clauses* → **catch** [*模式(pattern)*](TODO) _可选_ [*where-clause*](TODO) _可选_ [*代码块(code-block)*](TODO) _可选_
|
> *catch-clauses* → **catch** [*模式(pattern)*](TODO) _可选_ [*where-clause*](TODO) _可选_ [*代码块(code-block)*](TODO) _可选_
|
||||||
|
|
||||||
<a name="generic_parameters_and_arguments"></a>
|
<a name="generic_parameters_and_arguments"></a>
|
||||||
## 泛型参数
|
## 泛型参数
|
||||||
@ -216,7 +216,7 @@
|
|||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> 泛型实参从句语法
|
> 泛型实参从句语法
|
||||||
> *(泛型参数从句Generic Argument Clause)* → **<** [*泛型参数集*](GenericParametersAndArguments.html#generic_argument_list) **>**
|
> *(泛型参数从句 Generic Argument Clause)* → **<** [*泛型参数集*](GenericParametersAndArguments.html#generic_argument_list) **>**
|
||||||
> *泛型参数集* → [*泛型参数*](GenericParametersAndArguments.html#generic_argument) | [*泛型参数*](GenericParametersAndArguments.html#generic_argument) **,** [*泛型参数集*](GenericParametersAndArguments.html#generic_argument_list)
|
> *泛型参数集* → [*泛型参数*](GenericParametersAndArguments.html#generic_argument) | [*泛型参数*](GenericParametersAndArguments.html#generic_argument) **,** [*泛型参数集*](GenericParametersAndArguments.html#generic_argument_list)
|
||||||
> *泛型参数* → [*类型*](../chapter3/03_Types.html#type)
|
> *泛型参数* → [*类型*](../chapter3/03_Types.html#type)
|
||||||
|
|
||||||
@ -272,24 +272,24 @@
|
|||||||
> 变量声明语法
|
> 变量声明语法
|
||||||
> *变量声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*模式构造器集*](../chapter3/05_Declarations.html#pattern_initializer_list)
|
> *变量声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*模式构造器集*](../chapter3/05_Declarations.html#pattern_initializer_list)
|
||||||
> *变量声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*变量名*](../chapter3/05_Declarations.html#variable_name) [*类型注解*](../chapter3/03_Types.html#type_annotation) [*代码块*](../chapter3/05_Declarations.html#code_block)
|
> *变量声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*变量名*](../chapter3/05_Declarations.html#variable_name) [*类型注解*](../chapter3/03_Types.html#type_annotation) [*代码块*](../chapter3/05_Declarations.html#code_block)
|
||||||
> *变量声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*变量名*](../chapter3/05_Declarations.html#variable_name) [*类型注解*](../chapter3/03_Types.html#type_annotation) [*getter-setter块*](../chapter3/05_Declarations.html#getter_setter_block)
|
> *变量声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*变量名*](../chapter3/05_Declarations.html#variable_name) [*类型注解*](../chapter3/03_Types.html#type_annotation) [*getter-setter 块*](../chapter3/05_Declarations.html#getter_setter_block)
|
||||||
> *变量声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*变量名*](../chapter3/05_Declarations.html#variable_name) [*类型注解*](../chapter3/03_Types.html#type_annotation) [*getter-setter关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
|
> *变量声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*变量名*](../chapter3/05_Declarations.html#variable_name) [*类型注解*](../chapter3/03_Types.html#type_annotation) [*getter-setter 关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
|
||||||
> *变量声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*变量名*](../chapter3/05_Declarations.html#variable_name) [*类型注解*](../chapter3/03_Types.html#type_annotation) [*构造器*](../chapter3/05_Declarations.html#initializer) _可选_ [*willSet-didSet代码块*](../chapter3/05_Declarations.html#willSet_didSet_block)
|
> *变量声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*变量名*](../chapter3/05_Declarations.html#variable_name) [*类型注解*](../chapter3/03_Types.html#type_annotation) [*构造器*](../chapter3/05_Declarations.html#initializer) _可选_ [*willSet-didSet 代码块*](../chapter3/05_Declarations.html#willSet_didSet_block)
|
||||||
> *变量声明头(Head)* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ [*声明修改符(Modifers)集*](../chapter3/05_Declarations.html#declaration_specifiers) _可选_ **var**
|
> *变量声明头(Head)* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ [*声明修改符(Modifers)集*](../chapter3/05_Declarations.html#declaration_specifiers) _可选_ **var**
|
||||||
> *变量名称* → [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
> *变量名称* → [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
||||||
> *getter-setter块* → **{** [*getter从句*](../chapter3/05_Declarations.html#getter_clause) [*setter从句*](../chapter3/05_Declarations.html#setter_clause) _可选_ **}**
|
> *getter-setter 块* → **{** [*getter 从句*](../chapter3/05_Declarations.html#getter_clause) [*setter 从句*](../chapter3/05_Declarations.html#setter_clause) _可选_ **}**
|
||||||
> *getter-setter块* → **{** [*setter从句*](../chapter3/05_Declarations.html#setter_clause) [*getter从句*](../chapter3/05_Declarations.html#getter_clause) **}**
|
> *getter-setter 块* → **{** [*setter 从句*](../chapter3/05_Declarations.html#setter_clause) [*getter 从句*](../chapter3/05_Declarations.html#getter_clause) **}**
|
||||||
> *getter从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **get** [*代码块*](../chapter3/05_Declarations.html#code_block)
|
> *getter 从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **get** [*代码块*](../chapter3/05_Declarations.html#code_block)
|
||||||
> *setter从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **set** [*setter名称*](../chapter3/05_Declarations.html#setter_name) _可选_ [*代码块*](../chapter3/05_Declarations.html#code_block)
|
> *setter 从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **set** [*setter 名称*](../chapter3/05_Declarations.html#setter_name) _可选_ [*代码块*](../chapter3/05_Declarations.html#code_block)
|
||||||
> *setter名称* → **(** [*标识符*](../chapter3/02_Lexical_Structure.html#identifier) **)**
|
> *setter 名称* → **(** [*标识符*](../chapter3/02_Lexical_Structure.html#identifier) **)**
|
||||||
> *getter-setter关键字(Keyword)块* → **{** [*getter关键字(Keyword)从句*](../chapter3/05_Declarations.html#getter_keyword_clause) [*setter关键字(Keyword)从句*](../chapter3/05_Declarations.html#setter_keyword_clause) _可选_ **}**
|
> *getter-setter 关键字(Keyword)块* → **{** [*getter 关键字(Keyword)从句*](../chapter3/05_Declarations.html#getter_keyword_clause) [*setter 关键字(Keyword)从句*](../chapter3/05_Declarations.html#setter_keyword_clause) _可选_ **}**
|
||||||
> *getter-setter关键字(Keyword)块* → **{** [*setter关键字(Keyword)从句*](../chapter3/05_Declarations.html#setter_keyword_clause) [*getter关键字(Keyword)从句*](../chapter3/05_Declarations.html#getter_keyword_clause) **}**
|
> *getter-setter 关键字(Keyword)块* → **{** [*setter 关键字(Keyword)从句*](../chapter3/05_Declarations.html#setter_keyword_clause) [*getter 关键字(Keyword)从句*](../chapter3/05_Declarations.html#getter_keyword_clause) **}**
|
||||||
> *getter关键字(Keyword)从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **get**
|
> *getter 关键字(Keyword)从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **get**
|
||||||
> *setter关键字(Keyword)从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **set**
|
> *setter 关键字(Keyword)从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **set**
|
||||||
> *willSet-didSet代码块* → **{** [*willSet从句*](../chapter3/05_Declarations.html#willSet_clause) [*didSet从句*](../chapter3/05_Declarations.html#didSet_clause) _可选_ **}**
|
> *willSet-didSet 代码块* → **{** [*willSet 从句*](../chapter3/05_Declarations.html#willSet_clause) [*didSet 从句*](../chapter3/05_Declarations.html#didSet_clause) _可选_ **}**
|
||||||
> *willSet-didSet代码块* → **{** [*didSet从句*](../chapter3/05_Declarations.html#didSet_clause) [*willSet从句*](../chapter3/05_Declarations.html#willSet_clause) **}**
|
> *willSet-didSet 代码块* → **{** [*didSet 从句*](../chapter3/05_Declarations.html#didSet_clause) [*willSet 从句*](../chapter3/05_Declarations.html#willSet_clause) **}**
|
||||||
> *willSet从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **willSet** [*setter名称*](../chapter3/05_Declarations.html#setter_name) _可选_ [*代码块*](../chapter3/05_Declarations.html#code_block)
|
> *willSet 从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **willSet** [*setter 名称*](../chapter3/05_Declarations.html#setter_name) _可选_ [*代码块*](../chapter3/05_Declarations.html#code_block)
|
||||||
> *didSet从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **didSet** [*setter名称*](../chapter3/05_Declarations.html#setter_name) _可选_ [*代码块*](../chapter3/05_Declarations.html#code_block)
|
> *didSet 从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **didSet** [*setter 名称*](../chapter3/05_Declarations.html#setter_name) _可选_ [*代码块*](../chapter3/05_Declarations.html#code_block)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
@ -331,19 +331,19 @@
|
|||||||
|
|
||||||
> *联合样式枚举成员* → [*union-style-enum-member*](../chapter3/05_Declarations.html#union_style_enum_member) [*联合样式枚举成员*](../chapter3/05_Declarations.html#union_style_enum_members) _可选_
|
> *联合样式枚举成员* → [*union-style-enum-member*](../chapter3/05_Declarations.html#union_style_enum_member) [*联合样式枚举成员*](../chapter3/05_Declarations.html#union_style_enum_members) _可选_
|
||||||
|
|
||||||
> *联合样式枚举成员* → [*声明*](../chapter3/05_Declarations.html#declaration) | [*联合式(Union Style)的枚举case从句*](../chapter3/05_Declarations.html#union_style_enum_case_clause)
|
> *联合样式枚举成员* → [*声明*](../chapter3/05_Declarations.html#declaration) | [*联合式(Union Style)的枚举 case 从句*](../chapter3/05_Declarations.html#union_style_enum_case_clause)
|
||||||
|
|
||||||
> *联合式(Union Style)的枚举case从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **case** [*联合式(Union Style)的枚举case集*](../chapter3/05_Declarations.html#union_style_enum_case_list)
|
> *联合式(Union Style)的枚举 case 从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **case** [*联合式(Union Style)的枚举 case 集*](../chapter3/05_Declarations.html#union_style_enum_case_list)
|
||||||
> *联合式(Union Style)的枚举case集* → [*联合式(Union Style)的case*](../chapter3/05_Declarations.html#union_style_enum_case) | [*联合式(Union Style)的case*](../chapter3/05_Declarations.html#union_style_enum_case) **,** [*联合式(Union Style)的枚举case集*](../chapter3/05_Declarations.html#union_style_enum_case_list)
|
> *联合式(Union Style)的枚举 case 集* → [*联合式(Union Style)的 case*](../chapter3/05_Declarations.html#union_style_enum_case) | [*联合式(Union Style)的 case*](../chapter3/05_Declarations.html#union_style_enum_case) **,** [*联合式(Union Style)的枚举 case 集*](../chapter3/05_Declarations.html#union_style_enum_case_list)
|
||||||
> *联合式(Union Style)的枚举case* → [*枚举的case名*](../chapter3/05_Declarations.html#enum_case_name) [*元组类型*](../chapter3/03_Types.html#tuple_type) _可选_
|
> *联合式(Union Style)的枚举 case* → [*枚举的 case 名*](../chapter3/05_Declarations.html#enum_case_name) [*元组类型*](../chapter3/03_Types.html#tuple_type) _可选_
|
||||||
> *枚举名* → [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
> *枚举名* → [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
||||||
> *枚举的case名* → [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
> *枚举的 case 名* → [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
||||||
> *原始值式枚举* → **enum** [*枚举名*](../chapter3/05_Declarations.html#enum_name) [*泛型参数从句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ **:** [*类型标识*](../chapter3/03_Types.html#type_identifier) **{** [*原始值式枚举成员集*](../chapter3/05_Declarations.html#raw_value_style_enum_members) _可选_ **}**
|
> *原始值式枚举* → **enum** [*枚举名*](../chapter3/05_Declarations.html#enum_name) [*泛型参数从句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ **:** [*类型标识*](../chapter3/03_Types.html#type_identifier) **{** [*原始值式枚举成员集*](../chapter3/05_Declarations.html#raw_value_style_enum_members) _可选_ **}**
|
||||||
> *原始值式枚举成员集* → [*原始值式枚举成员*](../chapter3/05_Declarations.html#raw_value_style_enum_member) [*原始值式枚举成员集*](../chapter3/05_Declarations.html#raw_value_style_enum_members) _可选_
|
> *原始值式枚举成员集* → [*原始值式枚举成员*](../chapter3/05_Declarations.html#raw_value_style_enum_member) [*原始值式枚举成员集*](../chapter3/05_Declarations.html#raw_value_style_enum_members) _可选_
|
||||||
> *原始值式枚举成员* → [*声明*](../chapter3/05_Declarations.html#declaration) | [*原始值式枚举case从句*](../chapter3/05_Declarations.html#raw_value_style_enum_case_clause)
|
> *原始值式枚举成员* → [*声明*](../chapter3/05_Declarations.html#declaration) | [*原始值式枚举 case 从句*](../chapter3/05_Declarations.html#raw_value_style_enum_case_clause)
|
||||||
> *原始值式枚举case从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **case** [*原始值式枚举case集*](../chapter3/05_Declarations.html#raw_value_style_enum_case_list)
|
> *原始值式枚举 case 从句* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ **case** [*原始值式枚举 case 集*](../chapter3/05_Declarations.html#raw_value_style_enum_case_list)
|
||||||
> *原始值式枚举case集* → [*原始值式枚举case*](../chapter3/05_Declarations.html#raw_value_style_enum_case) | [*原始值式枚举case*](../chapter3/05_Declarations.html#raw_value_style_enum_case) **,** [*原始值式枚举case集*](../chapter3/05_Declarations.html#raw_value_style_enum_case_list)
|
> *原始值式枚举 case 集* → [*原始值式枚举 case*](../chapter3/05_Declarations.html#raw_value_style_enum_case) | [*原始值式枚举 case*](../chapter3/05_Declarations.html#raw_value_style_enum_case) **,** [*原始值式枚举 case 集*](../chapter3/05_Declarations.html#raw_value_style_enum_case_list)
|
||||||
> *原始值式枚举case* → [*枚举的case名*](../chapter3/05_Declarations.html#enum_case_name) [*原始值赋值*](../chapter3/05_Declarations.html#raw_value_assignment) _可选_
|
> *原始值式枚举 case* → [*枚举的 case 名*](../chapter3/05_Declarations.html#enum_case_name) [*原始值赋值*](../chapter3/05_Declarations.html#raw_value_assignment) _可选_
|
||||||
> *原始值赋值* → **=** [*字面量*](../chapter3/02_Lexical_Structure.html#literal)
|
> *原始值赋值* → **=** [*字面量*](../chapter3/02_Lexical_Structure.html#literal)
|
||||||
> *原始值字面量(raw-value-literal)* → [*数值字面量*](TODO) | [*字符串字面量*](TODO) | [*布尔字面量*](TODO)
|
> *原始值字面量(raw-value-literal)* → [*数值字面量*](TODO) | [*字符串字面量*](TODO) | [*布尔字面量*](TODO)
|
||||||
|
|
||||||
@ -377,7 +377,7 @@
|
|||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> 协议属性声明语法
|
> 协议属性声明语法
|
||||||
> *协议属性声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*变量名*](../chapter3/05_Declarations.html#variable_name) [*类型注解*](../chapter3/03_Types.html#type_annotation) [*getter-setter关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
|
> *协议属性声明* → [*变量声明头(Head)*](../chapter3/05_Declarations.html#variable_declaration_head) [*变量名*](../chapter3/05_Declarations.html#variable_name) [*类型注解*](../chapter3/03_Types.html#type_annotation) [*getter-setter 关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
@ -392,7 +392,7 @@
|
|||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> 协议下标声明语法
|
> 协议下标声明语法
|
||||||
> *协议下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
|
> *协议下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter 关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
@ -425,8 +425,8 @@
|
|||||||
|
|
||||||
> 下标声明语法
|
> 下标声明语法
|
||||||
> *下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*代码块*](../chapter3/05_Declarations.html#code_block)
|
> *下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*代码块*](../chapter3/05_Declarations.html#code_block)
|
||||||
> *下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter块*](../chapter3/05_Declarations.html#getter_setter_block)
|
> *下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter 块*](../chapter3/05_Declarations.html#getter_setter_block)
|
||||||
> *下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
|
> *下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter 关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
|
||||||
> *下标头(Head)* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ [*声明修改器(declaration-modifiers)*](TODO) _可选_ **subscript** [*参数从句*](../chapter3/05_Declarations.html#parameter_clause)
|
> *下标头(Head)* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ [*声明修改器(declaration-modifiers)*](TODO) _可选_ **subscript** [*参数从句*](../chapter3/05_Declarations.html#parameter_clause)
|
||||||
> *下标结果(Result)* → **->** [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ [*类型*](../chapter3/03_Types.html#type)
|
> *下标结果(Result)* → **->** [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ [*类型*](../chapter3/03_Types.html#type)
|
||||||
|
|
||||||
@ -499,7 +499,7 @@
|
|||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> 枚举用例模式语法
|
> 枚举用例模式语法
|
||||||
> *enum-case-pattern* → [*类型标识*](../chapter3/03_Types.html#type_identifier) _可选_ **.** [*枚举的case名*](../chapter3/05_Declarations.html#enum_case_name) [*元组模式*](../chapter3/07_Patterns.html#tuple_pattern) _可选_
|
> *enum-case-pattern* → [*类型标识*](../chapter3/03_Types.html#type_identifier) _可选_ **.** [*枚举的 case 名*](../chapter3/05_Declarations.html#enum_case_name) [*元组模式*](../chapter3/07_Patterns.html#tuple_pattern) _可选_
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
> 可选模式语法
|
> 可选模式语法
|
||||||
@ -508,9 +508,9 @@
|
|||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> 类型转换模式语法
|
> 类型转换模式语法
|
||||||
> *类型转换模式(type-casting-pattern)* → [*is模式*](../chapter3/07_Patterns.html#is_pattern) | [*as模式*](../chapter3/07_Patterns.html#as_pattern)
|
> *类型转换模式(type-casting-pattern)* → [*is 模式*](../chapter3/07_Patterns.html#is_pattern) | [*as 模式*](../chapter3/07_Patterns.html#as_pattern)
|
||||||
> *is模式* → **is** [*类型*](../chapter3/03_Types.html#type)
|
> *is 模式* → **is** [*类型*](../chapter3/03_Types.html#type)
|
||||||
> *as模式* → [*模式*](../chapter3/07_Patterns.html#pattern) **as** [*类型*](../chapter3/03_Types.html#type)
|
> *as 模式* → [*模式*](../chapter3/07_Patterns.html#pattern) **as** [*类型*](../chapter3/03_Types.html#type)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
@ -547,15 +547,15 @@
|
|||||||
> *写入写出(in-out)表达式* → **&** [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
> *写入写出(in-out)表达式* → **&** [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
> try表达式语法
|
> try 表达式语法
|
||||||
> *try-operator* → **try** | **try !**
|
> *try-operator* → **try** | **try !**
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> 二元表达式语法
|
> 二元表达式语法
|
||||||
> *二元表达式* → [*二元运算符*](../chapter3/02_Lexical_Structure.html#binary_operator) [*前置表达式*](../chapter3/04_Expressions.html#prefix_expression)
|
> *二元表达式* → [*二元运算符*](../chapter3/02_Lexical_Structure.html#binary_operator) [*前置表达式*](../chapter3/04_Expressions.html#prefix_expression)
|
||||||
> *二元表达式* → [*赋值运算符*](../chapter3/04_Expressions.html#assignment_operator) [*try运算符*](TODO) _可选_ [*前置表达式*](../chapter3/04_Expressions.html#prefix_expression)
|
> *二元表达式* → [*赋值运算符*](../chapter3/04_Expressions.html#assignment_operator) [*try 运算符*](TODO) _可选_ [*前置表达式*](../chapter3/04_Expressions.html#prefix_expression)
|
||||||
> *二元表达式* → [*条件运算符*](../chapter3/04_Expressions.html#conditional_operator) [*try运算符*](TODO) _可选_ [*前置表达式*](../chapter3/04_Expressions.html#prefix_expression)
|
> *二元表达式* → [*条件运算符*](../chapter3/04_Expressions.html#conditional_operator) [*try 运算符*](TODO) _可选_ [*前置表达式*](../chapter3/04_Expressions.html#prefix_expression)
|
||||||
> *二元表达式* → [*类型转换运算符*](../chapter3/04_Expressions.html#type_casting_operator)
|
> *二元表达式* → [*类型转换运算符*](../chapter3/04_Expressions.html#type_casting_operator)
|
||||||
> *二元表达式集* → [*二元表达式*](../chapter3/04_Expressions.html#binary_expression) [*二元表达式集*](../chapter3/04_Expressions.html#binary_expressions) _可选_
|
> *二元表达式集* → [*二元表达式*](../chapter3/04_Expressions.html#binary_expression) [*二元表达式集*](../chapter3/04_Expressions.html#binary_expressions) _可选_
|
||||||
|
|
||||||
@ -585,7 +585,7 @@
|
|||||||
> 主表达式语法
|
> 主表达式语法
|
||||||
> *主表达式* → [*标识符*](../chapter3/02_Lexical_Structure.html#identifier) [*泛型参数从句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_
|
> *主表达式* → [*标识符*](../chapter3/02_Lexical_Structure.html#identifier) [*泛型参数从句*](GenericParametersAndArguments.html#generic_argument_clause) _可选_
|
||||||
> *主表达式* → [*字面量表达式*](../chapter3/04_Expressions.html#literal_expression)
|
> *主表达式* → [*字面量表达式*](../chapter3/04_Expressions.html#literal_expression)
|
||||||
> *主表达式* → [*self表达式*](../chapter3/04_Expressions.html#self_expression)
|
> *主表达式* → [*self 表达式*](../chapter3/04_Expressions.html#self_expression)
|
||||||
> *主表达式* → [*超类表达式*](../chapter3/04_Expressions.html#superclass_expression)
|
> *主表达式* → [*超类表达式*](../chapter3/04_Expressions.html#superclass_expression)
|
||||||
> *主表达式* → [*闭包表达式*](../chapter3/04_Expressions.html#closure_expression)
|
> *主表达式* → [*闭包表达式*](../chapter3/04_Expressions.html#closure_expression)
|
||||||
> *主表达式* → [*圆括号表达式*](../chapter3/04_Expressions.html#parenthesized_expression)
|
> *主表达式* → [*圆括号表达式*](../chapter3/04_Expressions.html#parenthesized_expression)
|
||||||
@ -608,10 +608,10 @@
|
|||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> Self 表达式语法
|
> Self 表达式语法
|
||||||
> *self表达式* → **self**
|
> *self 表达式* → **self**
|
||||||
> *self表达式* → **self** **.** [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
> *self 表达式* → **self** **.** [*标识符*](../chapter3/02_Lexical_Structure.html#identifier)
|
||||||
> *self表达式* → **self** **[** [*表达式*](../chapter3/04_Expressions.html#expression) **]**
|
> *self 表达式* → **self** **[** [*表达式*](../chapter3/04_Expressions.html#expression) **]**
|
||||||
> *self表达式* → **self** **.** **init**
|
> *self 表达式* → **self** **.** **init**
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
@ -658,7 +658,7 @@
|
|||||||
> *后置表达式* → [*函数调用表达式*](../chapter3/04_Expressions.html#function_call_expression)
|
> *后置表达式* → [*函数调用表达式*](../chapter3/04_Expressions.html#function_call_expression)
|
||||||
> *后置表达式* → [*构造器表达式*](../chapter3/04_Expressions.html#initializer_expression)
|
> *后置表达式* → [*构造器表达式*](../chapter3/04_Expressions.html#initializer_expression)
|
||||||
> *后置表达式* → [*显示成员表达式*](../chapter3/04_Expressions.html#explicit_member_expression)
|
> *后置表达式* → [*显示成员表达式*](../chapter3/04_Expressions.html#explicit_member_expression)
|
||||||
> *后置表达式* → [*后置self表达式*](../chapter3/04_Expressions.html#postfix_self_expression)
|
> *后置表达式* → [*后置 self 表达式*](../chapter3/04_Expressions.html#postfix_self_expression)
|
||||||
> *后置表达式* → [*动态类型表达式*](../chapter3/04_Expressions.html#dynamic_type_expression)
|
> *后置表达式* → [*动态类型表达式*](../chapter3/04_Expressions.html#dynamic_type_expression)
|
||||||
> *后置表达式* → [*下标表达式*](../chapter3/04_Expressions.html#subscript_expression)
|
> *后置表达式* → [*下标表达式*](../chapter3/04_Expressions.html#subscript_expression)
|
||||||
> *后置表达式* → [*强制取值(Forced Value)表达式*](../chapter3/04_Expressions.html#forced_value_expression)
|
> *后置表达式* → [*强制取值(Forced Value)表达式*](../chapter3/04_Expressions.html#forced_value_expression)
|
||||||
@ -684,8 +684,8 @@
|
|||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
> 后置Self 表达式语法
|
> 后置 Self 表达式语法
|
||||||
> *后置self表达式* → [*后置表达式*](../chapter3/04_Expressions.html#postfix_expression) **.** **self**
|
> *后置 self 表达式* → [*后置表达式*](../chapter3/04_Expressions.html#postfix_expression) **.** **self**
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
@ -781,12 +781,12 @@
|
|||||||
> *浮点数字面量* → [*十进制字面量*](../chapter3/02_Lexical_Structure.html#decimal_literal) [*十进制分数*](../chapter3/02_Lexical_Structure.html#decimal_fraction) _可选_ [*十进制指数*](../chapter3/02_Lexical_Structure.html#decimal_exponent) _可选_
|
> *浮点数字面量* → [*十进制字面量*](../chapter3/02_Lexical_Structure.html#decimal_literal) [*十进制分数*](../chapter3/02_Lexical_Structure.html#decimal_fraction) _可选_ [*十进制指数*](../chapter3/02_Lexical_Structure.html#decimal_exponent) _可选_
|
||||||
> *浮点数字面量* → [*十六进制字面量*](../chapter3/02_Lexical_Structure.html#hexadecimal_literal) [*十六进制分数*](../chapter3/02_Lexical_Structure.html#hexadecimal_fraction) _可选_ [*十六进制指数*](../chapter3/02_Lexical_Structure.html#hexadecimal_exponent)
|
> *浮点数字面量* → [*十六进制字面量*](../chapter3/02_Lexical_Structure.html#hexadecimal_literal) [*十六进制分数*](../chapter3/02_Lexical_Structure.html#hexadecimal_fraction) _可选_ [*十六进制指数*](../chapter3/02_Lexical_Structure.html#hexadecimal_exponent)
|
||||||
> *十进制分数* → **.** [*十进制字面量*](../chapter3/02_Lexical_Structure.html#decimal_literal)
|
> *十进制分数* → **.** [*十进制字面量*](../chapter3/02_Lexical_Structure.html#decimal_literal)
|
||||||
> *十进制指数* → [*浮点数e*](../chapter3/02_Lexical_Structure.html#floating_point_e) [*正负号*](../chapter3/02_Lexical_Structure.html#sign) _可选_ [*十进制字面量*](../chapter3/02_Lexical_Structure.html#decimal_literal)
|
> *十进制指数* → [*浮点数 e*](../chapter3/02_Lexical_Structure.html#floating_point_e) [*正负号*](../chapter3/02_Lexical_Structure.html#sign) _可选_ [*十进制字面量*](../chapter3/02_Lexical_Structure.html#decimal_literal)
|
||||||
> *十六进制分数* → **.** [*十六进制数*](../chapter3/02_Lexical_Structure.html#hexadecimal_literal)
|
> *十六进制分数* → **.** [*十六进制数*](../chapter3/02_Lexical_Structure.html#hexadecimal_literal)
|
||||||
[*十六进制字面量字符集*](TODO)_可选_
|
[*十六进制字面量字符集*](TODO)_可选_
|
||||||
> *十六进制指数* → [*浮点数p*](../chapter3/02_Lexical_Structure.html#floating_point_p) [*正负号*](../chapter3/02_Lexical_Structure.html#sign) _可选_ [*十六进制字面量*](../chapter3/02_Lexical_Structure.html#hexadecimal_literal)
|
> *十六进制指数* → [*浮点数 p*](../chapter3/02_Lexical_Structure.html#floating_point_p) [*正负号*](../chapter3/02_Lexical_Structure.html#sign) _可选_ [*十六进制字面量*](../chapter3/02_Lexical_Structure.html#hexadecimal_literal)
|
||||||
> *浮点数e* → **e** | **E**
|
> *浮点数 e* → **e** | **E**
|
||||||
> *浮点数p* → **p** | **P**
|
> *浮点数 p* → **p** | **P**
|
||||||
> *正负号* → **+** | **-**
|
> *正负号* → **+** | **-**
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
@ -796,10 +796,10 @@
|
|||||||
> *引用文本* → [*引用文本条目*](../chapter3/02_Lexical_Structure.html#quoted_text_item) [*引用文本*](../chapter3/02_Lexical_Structure.html#quoted_text) _可选_
|
> *引用文本* → [*引用文本条目*](../chapter3/02_Lexical_Structure.html#quoted_text_item) [*引用文本*](../chapter3/02_Lexical_Structure.html#quoted_text) _可选_
|
||||||
> *引用文本条目* → [*转义字符*](../chapter3/02_Lexical_Structure.html#escaped_character)
|
> *引用文本条目* → [*转义字符*](../chapter3/02_Lexical_Structure.html#escaped_character)
|
||||||
> *引用文本条目* → **(** [*表达式*](../chapter3/04_Expressions.html#expression) **)**
|
> *引用文本条目* → **(** [*表达式*](../chapter3/04_Expressions.html#expression) **)**
|
||||||
> *引用文本条目* → 除了", \, U+000A, or U+000D的所有Unicode的字符
|
> *引用文本条目* → 除了", \, U+000A, or U+000D 的所有 Unicode 的字符
|
||||||
> *转义字符* → **/0** | **\\** | **\t** | **\n** | **\r** | **\"** | **\'**
|
> *转义字符* → **/0** | **\\** | **\t** | **\n** | **\r** | **\"** | **\'**
|
||||||
> *转义字符* → **\u** **{** [*十六进制标量数字集*](TODO) **}**
|
> *转义字符* → **\u** **{** [*十六进制标量数字集*](TODO) **}**
|
||||||
> *unicode标量数字集* → Between one and eight hexadecimal digits
|
> *unicode 标量数字集* → Between one and eight hexadecimal digits
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
|
|||||||
@ -5,15 +5,15 @@
|
|||||||
|
|
||||||
如果您之前没有接触过权限控制,先来听一个小故事:
|
如果您之前没有接触过权限控制,先来听一个小故事:
|
||||||
|
|
||||||
> 小明是五道口工业学院的一个大一新生,最近他有点烦恼,因为同屋经常用他的热水壶,好像那是自己家的一样,可是碍于同学情面,又不好意思说。直到有一天,他和学姐小K吐槽。
|
> 小明是五道口工业学院的一个大一新生,最近他有点烦恼,因为同屋经常用他的热水壶,好像那是自己家的一样,可是碍于同学情面,又不好意思说。直到有一天,他和学姐小 K 吐槽。
|
||||||
|
|
||||||
> 学姐听了之后,说:大学集体生活里面,大部分东西都是默认室友可以共用的。如果你不想别人拿,我可以帮你做封印,只要打上private标记,它们就看不到你的东西,更加用不了你的东西了。
|
> 学姐听了之后,说:大学集体生活里面,大部分东西都是默认室友可以共用的。如果你不想别人拿,我可以帮你做封印,只要打上 private 标记,它们就看不到你的东西,更加用不了你的东西了。
|
||||||
|
|
||||||
> 小明说哇靠学姐你还会妖法......
|
> 小明说哇靠学姐你还会妖法......
|
||||||
|
|
||||||
Swift语言从Xcode 6 beta 5版本起,加入了对权限控制(Access Control)的支持。其实权限控制和小明的物品一样,你可以设定水壶是只有自己能用,还是只有宿舍里的人能用,还是全校都可以用。
|
Swift 语言从 Xcode 6 beta 5版本起,加入了对权限控制(Access Control)的支持。其实权限控制和小明的物品一样,你可以设定水壶是只有自己能用,还是只有宿舍里的人能用,还是全校都可以用。
|
||||||
|
|
||||||
从此以后,你可以好像神盾局局长一样,完全掌控自己的代码块的”保密级别“,哪些是只能在本文件引用,哪些能用在整个项目里,你还可以发挥大爱精神,把它开源成只要导入你的框架,大家都可以使用的API。
|
从此以后,你可以好像神盾局局长一样,完全掌控自己的代码块的”保密级别“,哪些是只能在本文件引用,哪些能用在整个项目里,你还可以发挥大爱精神,把它开源成只要导入你的框架,大家都可以使用的 API。
|
||||||
|
|
||||||
这三种权限分别是:
|
这三种权限分别是:
|
||||||
|
|
||||||
@ -23,29 +23,29 @@ Swift语言从Xcode 6 beta 5版本起,加入了对权限控制(Access Contro
|
|||||||
|
|
||||||
- #####internal 内部的
|
- #####internal 内部的
|
||||||
|
|
||||||
标记为internal的代码块,在整个应用(App bundle)或者框架(framework)的范围内都是可以访问的。
|
标记为 internal 的代码块,在整个应用(App bundle)或者框架(framework)的范围内都是可以访问的。
|
||||||
|
|
||||||
- #####public 公开的
|
- #####public 公开的
|
||||||
|
|
||||||
标记为public的代码块一般用来建立API,这是最开放的权限,使得任何人只要导入这个模块,都可以访问使用。
|
标记为 public 的代码块一般用来建立 API,这是最开放的权限,使得任何人只要导入这个模块,都可以访问使用。
|
||||||
|
|
||||||
如果要把所有的爱加上一个期限,噢不,是给所有的代码块都标记上权限,不累死才怪。还好swift里面所有代码实体的默认权限,都是最常用的internal。所以当你开发自己的App时,可能完全不用管权限控制的事情。
|
如果要把所有的爱加上一个期限,噢不,是给所有的代码块都标记上权限,不累死才怪。还好 swift 里面所有代码实体的默认权限,都是最常用的 internal。所以当你开发自己的 App 时,可能完全不用管权限控制的事情。
|
||||||
|
|
||||||
但当你需要写一个公开API的时候,就必须对里面的代码块进行“隐身对其可见”的public标记,要么其他人是用不到的。
|
但当你需要写一个公开 API 的时候,就必须对里面的代码块进行“隐身对其可见”的 public 标记,要么其他人是用不到的。
|
||||||
|
|
||||||
Private(私有级别)的权限最严格,它可以用来隐藏某些功能的细节实现方式。合理构筑你的代码,你就可以安全地使用extension和高级功能,又不把它们暴露给项目内的其他文件。
|
Private(私有级别)的权限最严格,它可以用来隐藏某些功能的细节实现方式。合理构筑你的代码,你就可以安全地使用 extension 和高级功能,又不把它们暴露给项目内的其他文件。
|
||||||
|
|
||||||
除了可以给整个声明设权限,Swift还允许大家在需要的时候,把某个属性(property)的取值权限比赋值权限设得更加开放。
|
除了可以给整个声明设权限,Swift 还允许大家在需要的时候,把某个属性(property)的取值权限比赋值权限设得更加开放。
|
||||||
|
|
||||||
#####举个例子:
|
#####举个例子:
|
||||||
```swift
|
```swift
|
||||||
public class ListItem {
|
public class ListItem {
|
||||||
|
|
||||||
// ListItem这个类,有两个公开的属性
|
// ListItem 这个类,有两个公开的属性
|
||||||
public var text: String
|
public var text: String
|
||||||
public var isComplete: Bool
|
public var isComplete: Bool
|
||||||
|
|
||||||
// 下面的代码表示把变量UUID的赋值权限设为private,对整个app可读,但值只能在本文件里写入
|
// 下面的代码表示把变量 UUID 的赋值权限设为 private,对整个 app 可读,但值只能在本文件里写入
|
||||||
private(set) var UUID: NSUUID
|
private(set) var UUID: NSUUID
|
||||||
|
|
||||||
public init(text: String, completed: Bool, UUID: NSUUID) {
|
public init(text: String, completed: Bool, UUID: NSUUID) {
|
||||||
@ -54,7 +54,7 @@ Private(私有级别)的权限最严格,它可以用来隐藏某些功能
|
|||||||
self.UUID = UUID
|
self.UUID = UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
// 这段没有特别标记权限,因此属于默认的internal级别。在框架目标内可用,但对于其他目标不可用
|
// 这段没有特别标记权限,因此属于默认的 internal 级别。在框架目标内可用,但对于其他目标不可用
|
||||||
func refreshIdentity() {
|
func refreshIdentity() {
|
||||||
self.UUID = NSUUID()
|
self.UUID = NSUUID()
|
||||||
}
|
}
|
||||||
@ -68,15 +68,15 @@ Private(私有级别)的权限最严格,它可以用来隐藏某些功能
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
当我们使用Objective-C和Swift混合开发时,需要注意:
|
当我们使用 Objective-C 和 Swift 混合开发时,需要注意:
|
||||||
|
|
||||||
- 如果你在写的是一个应用,Xcode会生成一个头文件来保证两者的可互访性,而这个生成的头文件会包含public和internal级别的声明。
|
- 如果你在写的是一个应用,Xcode 会生成一个头文件来保证两者的可互访性,而这个生成的头文件会包含 public 和 internal 级别的声明。
|
||||||
|
|
||||||
- 如果你的最终产品是一个Swift框架,头文件里只会出现标记为public级别的声明。(因为框架的头文件,属于公开的Objective-C接口的一部分,只有public部分对Objective-C可用。)
|
- 如果你的最终产品是一个 Swift 框架,头文件里只会出现标记为 public 级别的声明。(因为框架的头文件,属于公开的 Objective-C 接口的一部分,只有 public 部分对 Objective-C 可用。)
|
||||||
|
|
||||||
虽然Swift不推荐大家传播和使用第三方的框架,但对于建立和分享源文件形式的框架是支持的。对于需要写框架,方便应用与多个项目的开发者来说,要记得把API标记为public级别。
|
虽然 Swift 不推荐大家传播和使用第三方的框架,但对于建立和分享源文件形式的框架是支持的。对于需要写框架,方便应用与多个项目的开发者来说,要记得把 API 标记为 public 级别。
|
||||||
|
|
||||||
如果您想了解更多关于权限控制的内容,可以查看苹果官方最新的《The Swift Language》和《Using Swift with Cocoa and Objective-C》指南,
|
如果您想了解更多关于权限控制的内容,可以查看苹果官方最新的《The Swift Language》和《Using Swift with Cocoa and Objective-C》指南,
|
||||||
这两本指南在iBooks里面可以下载更新喔。
|
这两本指南在 iBooks 里面可以下载更新喔。
|
||||||
|
|
||||||
本文由翻译自Apple Swift Blog :https://developer.apple.com/swift/blog/?id=5
|
本文由翻译自 Apple Swift Blog :https://developer.apple.com/swift/blog/?id=5
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# 造个类型不是梦-白话Swift类型创建
|
# 造个类型不是梦-白话 Swift 类型创建
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
> 翻译:[老码团队翻译组-Tyrion](http://weibo.com/u/5241713117)
|
> 翻译:[老码团队翻译组-Tyrion](http://weibo.com/u/5241713117)
|
||||||
@ -9,17 +9,17 @@
|
|||||||
- [自定义原型](#prototype)
|
- [自定义原型](#prototype)
|
||||||
- [实现默认值](#imp-default)
|
- [实现默认值](#imp-default)
|
||||||
- [支持基本布尔型初始化](#init-by-bool)
|
- [支持基本布尔型初始化](#init-by-bool)
|
||||||
- [支持Bool类型判断](#condition-by-bool)
|
- [支持 Bool 类型判断](#condition-by-bool)
|
||||||
- [支持兼容各们各派的类型](#support-all-type)
|
- [支持兼容各们各派的类型](#support-all-type)
|
||||||
- [完善OCBool的布尔基因体系](#make-up-type)
|
- [完善 OCBool 的布尔基因体系](#make-up-type)
|
||||||
|
|
||||||
小伙伴们,Swift中的Bool类型有着非常重要的语法功能,并支撑起了整个Swift体系中的逻辑判断体系,经过老码的研究和学习, Bool类型本身其实是对基础Boolean类型封装,小伙伴们可能咬着手指头问老码,怎么一会Bool类型,一会Boolean类型,其区别在于,前者是基于枚举的组合类型,而后者则是基本类型,只有两种true和false。
|
小伙伴们,Swift 中的 Bool 类型有着非常重要的语法功能,并支撑起了整个 Swift 体系中的逻辑判断体系,经过老码的研究和学习, Bool 类型本身其实是对基础 Boolean 类型封装,小伙伴们可能咬着手指头问老码,怎么一会 Bool 类型,一会 Boolean 类型,其区别在于,前者是基于枚举的组合类型,而后者则是基本类型,只有两种 true 和 false。
|
||||||
|
|
||||||
<a name="prefix_expressions"></a>
|
<a name="prefix_expressions"></a>
|
||||||
####自定义原型
|
####自定义原型
|
||||||
|
|
||||||
接下老码根据Bool的思想来创建一个OCBool类型,来让小伙伴们了解一下Swift中到底是怎么玩儿的。
|
接下老码根据 Bool 的思想来创建一个 OCBool 类型,来让小伙伴们了解一下 Swift 中到底是怎么玩儿的。
|
||||||
来我们先看一下OCBool的定义。
|
来我们先看一下 OCBool 的定义。
|
||||||
|
|
||||||
#####代码示例如下:
|
#####代码示例如下:
|
||||||
|
|
||||||
@ -32,13 +32,13 @@ case ocFalse
|
|||||||
|
|
||||||
#####注意:
|
#####注意:
|
||||||
|
|
||||||
- 代码中第2行和第3行,可以合并到一行写,如苹果官方Blog所写的一样
|
- 代码中第2行和第3行,可以合并到一行写,如苹果官方 Blog 所写的一样
|
||||||
- 代码中命名需要注意:OCBool是类型名,所以首字母必须大写,而case中的ocTrue和ocFalse是小类型则需要首字母小写。
|
- 代码中命名需要注意:OCBool 是类型名,所以首字母必须大写,而 case 中的 ocTrue 和 ocFalse 是小类型则需要首字母小写。
|
||||||
|
|
||||||
<a name="imp-default"></a>
|
<a name="imp-default"></a>
|
||||||
####实现默认值
|
####实现默认值
|
||||||
|
|
||||||
行,我们给了一个漂亮的定义,不过按照传统语言的经验,Bool值默认情况下是假, 所以我们的OCBool也应该如此,我们使用类型扩展技术增加这个默认特性:
|
行,我们给了一个漂亮的定义,不过按照传统语言的经验,Bool 值默认情况下是假, 所以我们的 OCBool 也应该如此,我们使用类型扩展技术增加这个默认特性:
|
||||||
```swift
|
```swift
|
||||||
extension OCBool{
|
extension OCBool{
|
||||||
init(){
|
init(){
|
||||||
@ -49,9 +49,9 @@ extension OCBool{
|
|||||||
|
|
||||||
#####注意:
|
#####注意:
|
||||||
|
|
||||||
- 代码中第1行:extension关键字,非常强大,小伙伴们可以通过此创造出许多好玩的东西,建议各位去Github上看一个名为“Swiftz”的项目,它将扩展用到了极致。
|
- 代码中第1行:extension 关键字,非常强大,小伙伴们可以通过此创造出许多好玩的东西,建议各位去 Github 上看一个名为“Swiftz”的项目,它将扩展用到了极致。
|
||||||
- 代码中第3行:self = .ocFalse语法,刚入门的小伙伴们很迷糊,为什么会有奇怪的点语法,因为大牛Chris在Swift中增加了类型智能推断功能,在苹果Blog中,提到了“Context”概念,就是这个意思,因为这行语句是在枚举OCBool中的,其上下文就是OCBool的定义体,编译器当然知道.ocFalse就是OCBool.ocFalse了,所以这里直接点语法,非常整齐。
|
- 代码中第3行:self = .ocFalse 语法,刚入门的小伙伴们很迷糊,为什么会有奇怪的点语法,因为大牛 Chris 在 Swift 中增加了类型智能推断功能,在苹果 Blog 中,提到了“Context”概念,就是这个意思,因为这行语句是在枚举 OCBool 中的,其上下文就是 OCBool 的定义体,编译器当然知道.ocFalse 就是 OCBool.ocFalse 了,所以这里直接点语法,非常整齐。
|
||||||
现在我们可以使用如下方法使用这个Bool类型。
|
现在我们可以使用如下方法使用这个 Bool 类型。
|
||||||
|
|
||||||
#####代码示例如下:
|
#####代码示例如下:
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ var result1:OCBool = .ocTrue
|
|||||||
<a name="init-by-bool"></a>
|
<a name="init-by-bool"></a>
|
||||||
####支持基本布尔型初始化
|
####支持基本布尔型初始化
|
||||||
|
|
||||||
正如上述代码所述,我们只能通过类型或者枚举项目赋值,这是组合类型的用法,但是编码的日子里,我们总是希望和true,false直接打交道,也就是说,我们希望这么做,
|
正如上述代码所述,我们只能通过类型或者枚举项目赋值,这是组合类型的用法,但是编码的日子里,我们总是希望和 true,false 直接打交道,也就是说,我们希望这么做,
|
||||||
代码示例如下:
|
代码示例如下:
|
||||||
```swift
|
```swift
|
||||||
var isSuccess:OCBool = true
|
var isSuccess:OCBool = true
|
||||||
@ -97,7 +97,7 @@ var isSuccess:OCBool = true
|
|||||||
|
|
||||||
#####注意:
|
#####注意:
|
||||||
|
|
||||||
- 代码中的第11行是重点,我的类型OCBool支持了BooleanLiteralConvertible协议,这个协到底是干什么的呢,小伙伴们在Xcode代码编辑器,按住Command键,然后点击第11行中的BooleanLiteralConvertible协议名,则会进入它的定义,
|
- 代码中的第11行是重点,我的类型 OCBool 支持了 BooleanLiteralConvertible 协议,这个协到底是干什么的呢,小伙伴们在 Xcode 代码编辑器,按住 Command 键,然后点击第11行中的 BooleanLiteralConvertible 协议名,则会进入它的定义,
|
||||||
#####其定义如下:
|
#####其定义如下:
|
||||||
```swift
|
```swift
|
||||||
protocol BooleanLiteralConvertible {
|
protocol BooleanLiteralConvertible {
|
||||||
@ -106,10 +106,10 @@ protocol BooleanLiteralConvertible {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- 这个定义中有个类方法convertFromBooleanLiteral,它的参数为BooleanLiteralType类型,也就是我传入的Bool类型, 且返回值为实现这个协议的类型本身,在我们的OCBool类型中,其返回值就是OCBool本身。经过这个定义,我们可以直接对OCBool类型直接进行布尔字面量初始化了。
|
- 这个定义中有个类方法 convertFromBooleanLiteral,它的参数为 BooleanLiteralType 类型,也就是我传入的 Bool 类型, 且返回值为实现这个协议的类型本身,在我们的 OCBool 类型中,其返回值就是 OCBool 本身。经过这个定义,我们可以直接对 OCBool 类型直接进行布尔字面量初始化了。
|
||||||
|
|
||||||
<a name="condition-by-bool"></a>
|
<a name="condition-by-bool"></a>
|
||||||
####支持Bool类型判断
|
####支持 Bool 类型判断
|
||||||
|
|
||||||
小伙伴们不安分, 肯定想着我怎么用它实现逻辑判断,所以如果你这么写,
|
小伙伴们不安分, 肯定想着我怎么用它实现逻辑判断,所以如果你这么写,
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ if isSuccess {
|
|||||||
```
|
```
|
||||||
/Users/tyrion-OldCoder/Documents/Learning/BoolType/BoolType/main.swift:27:4: Type 'OCBool' does not conform to protocol 'LogicValue'
|
/Users/tyrion-OldCoder/Documents/Learning/BoolType/BoolType/main.swift:27:4: Type 'OCBool' does not conform to protocol 'LogicValue'
|
||||||
```
|
```
|
||||||
OCBool现在只能用bool类型初始化,而不能直接返回bool型,小火把们还记得在《老码说编程之白话Swift江湖》中,老码多次提到,妈妈再也不担心我们 if a = 1{}的写法了, 因为等号不支持值返回了, 所以在if判断是后面的条件必须有返回值,OCBool没有,所以编译器哭了。我们解决这个问题。
|
OCBool 现在只能用 bool 类型初始化,而不能直接返回 bool 型,小火把们还记得在《老码说编程之白话 Swift 江湖》中,老码多次提到,妈妈再也不担心我们 if a = 1{}的写法了, 因为等号不支持值返回了, 所以在 if 判断是后面的条件必须有返回值,OCBool 没有,所以编译器哭了。我们解决这个问题。
|
||||||
|
|
||||||
#####代码示例如下:
|
#####代码示例如下:
|
||||||
|
|
||||||
@ -178,14 +178,14 @@ Program ended with exit code: 0
|
|||||||
|
|
||||||
#####注意:
|
#####注意:
|
||||||
|
|
||||||
- 如果小伙伴们现在用的是Beta版的Xcode,注意苹果官方Blog中,在代码第17行如果在Xcode Beta4下是错误的,这里的协议是,LogicValue而不是BooleanVue,所以记得看错误提示才是好习惯。
|
- 如果小伙伴们现在用的是 Beta 版的 Xcode,注意苹果官方 Blog 中,在代码第17行如果在 Xcode Beta4下是错误的,这里的协议是,LogicValue 而不是 BooleanVue,所以记得看错误提示才是好习惯。
|
||||||
- 注意代码第34行,完美支持if判断,且输出结果为“老码请你吃火锅”,老码也是说说而已,请不要当真。
|
- 注意代码第34行,完美支持 if 判断,且输出结果为“老码请你吃火锅”,老码也是说说而已,请不要当真。
|
||||||
|
|
||||||
<a name="support-all-type"></a>
|
<a name="support-all-type"></a>
|
||||||
|
|
||||||
####支持兼容各们各派的类型
|
####支持兼容各们各派的类型
|
||||||
|
|
||||||
小伙伴们,江湖风险,门派众多,老码有自己的OCBool类型,可能嵩山少林有自己的SSBool类型,甚至连郭美美都可能有自己的MMBool类型,所以OCBool必须能够识别这些类型,这些各门各派的类型,只要支持LogicValue协议,就应该可以被识别,看老码怎么做,
|
小伙伴们,江湖风险,门派众多,老码有自己的 OCBool 类型,可能嵩山少林有自己的 SSBool 类型,甚至连郭美美都可能有自己的 MMBool 类型,所以 OCBool 必须能够识别这些类型,这些各门各派的类型,只要支持 LogicValue 协议,就应该可以被识别,看老码怎么做,
|
||||||
|
|
||||||
#####代码示例如下:
|
#####代码示例如下:
|
||||||
|
|
||||||
@ -218,16 +218,16 @@ Hello, World!
|
|||||||
老码没钱,郭美美请你吃火锅!
|
老码没钱,郭美美请你吃火锅!
|
||||||
Program ended with exit code: 0
|
Program ended with exit code: 0
|
||||||
```
|
```
|
||||||
漂亮!我们的OCBool类型现在支持了所有的逻辑变量初始化。
|
漂亮!我们的 OCBool 类型现在支持了所有的逻辑变量初始化。
|
||||||
|
|
||||||
#####注意:
|
#####注意:
|
||||||
|
|
||||||
- 代码中第2行:“_”下横杠的用法,这是一个功能强大的小强,在此的目的是屏蔽外部参数名,所以小伙伴们可以直接:var ocResult:OCBool = OCBool(mmResult)而不是:var ocResult:OCBool = OCBool(v: mmResult),小伙伴们惊呆了!这个init函数中本来就没有外部参数名啊,还记得老码在书里说过没,Swift的初始化函数会默认使用内部参数名,作为外部参数名。
|
- 代码中第2行:“_”下横杠的用法,这是一个功能强大的小强,在此的目的是屏蔽外部参数名,所以小伙伴们可以直接:var ocResult:OCBool = OCBool(mmResult)而不是:var ocResult:OCBool = OCBool(v: mmResult),小伙伴们惊呆了!这个 init 函数中本来就没有外部参数名啊,还记得老码在书里说过没,Swift 的初始化函数会默认使用内部参数名,作为外部参数名。
|
||||||
|
|
||||||
<a name="make-up-type"></a>
|
<a name="make-up-type"></a>
|
||||||
####完善OCBool的布尔基因体系:
|
####完善 OCBool 的布尔基因体系:
|
||||||
|
|
||||||
小伙伴们,bool类型的价值就是在于各种判断,诸如==,!=, &,|,^,!,以及各种组合逻辑运算,我们OCBool也要具备这些功能,否则就会基因缺陷,且看老码如何实现:
|
小伙伴们,bool 类型的价值就是在于各种判断,诸如==,!=, &,|,^,!,以及各种组合逻辑运算,我们 OCBool 也要具备这些功能,否则就会基因缺陷,且看老码如何实现:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
extension OCBool: Equatable{
|
extension OCBool: Equatable{
|
||||||
@ -294,6 +294,6 @@ if (isHasMoney | isHasHealty) & isHasHealty{
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
好了,到这里就到这里了,窗外的雷声叫醒了老码,现在应该去吃饭了,以上老码给大家展示了如果制造一个自己的类型,记得老码的示例是在Xcode6 Beta4下测试的,至于Beta5的改变还没有涉及,小伙伴们要好生练习,以后各种自定类型都是基于这个思想。还有这个章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码官方微博:http://weibo.com/u/5241713117咆哮。
|
好了,到这里就到这里了,窗外的雷声叫醒了老码,现在应该去吃饭了,以上老码给大家展示了如果制造一个自己的类型,记得老码的示例是在 Xcode6 Beta4下测试的,至于 Beta5的改变还没有涉及,小伙伴们要好生练习,以后各种自定类型都是基于这个思想。还有这个章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码官方微博:http://weibo.com/u/5241713117咆哮。
|
||||||
|
|
||||||
本文由翻译自Apple Swift Blog :https://developer.apple.com/swift/blog/?id=8
|
本文由翻译自 Apple Swift Blog :https://developer.apple.com/swift/blog/?id=8
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
# WWDC里面的那个“大炮打气球”
|
# WWDC 里面的那个“大炮打气球”
|
||||||
|
|
||||||
> 翻译:[老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
> 翻译:[老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
||||||
> 校对:[老码团队翻译组-](Jame)
|
> 校对:[老码团队翻译组-](Jame)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
很多小伙伴说,对WWDC上介绍Swift语言时,演示的那个“大炮打气球”的Ballons项目很感兴趣。
|
很多小伙伴说,对 WWDC 上介绍 Swift 语言时,演示的那个“大炮打气球”的 Ballons 项目很感兴趣。
|
||||||
|
|
||||||
Ballons不但展现了playgrounds许多很赞的特性,还让我们看到写代码的过程,原来可以这么互动,这么好玩。
|
Ballons 不但展现了 playgrounds 许多很赞的特性,还让我们看到写代码的过程,原来可以这么互动,这么好玩。
|
||||||
|
|
||||||
现在你可以下载这个[Ballons.playground](https://developer.apple.com/swift/blog/downloads/Balloons.zip)的教学版本,学习这些有趣的效果是怎么实现的。教学版本里除了源文件,还有相关说明文档,我们还出了一些小小的实验题,你可以动手修改代码,然后在右侧马上看到效果。
|
现在你可以下载这个[Ballons.playground](https://developer.apple.com/swift/blog/downloads/Balloons.zip)的教学版本,学习这些有趣的效果是怎么实现的。教学版本里除了源文件,还有相关说明文档,我们还出了一些小小的实验题,你可以动手修改代码,然后在右侧马上看到效果。
|
||||||
|
|
||||||
这个playground文件用到了SpriteKit的新特性,因此需要最新beta版本的Xcode 6和Yosemite系统来支持它运行。
|
这个 playground 文件用到了 SpriteKit 的新特性,因此需要最新 beta 版本的 Xcode 6和 Yosemite 系统来支持它运行。
|
||||||
|
|
||||||
本文由翻译自Apple Swift Blog的博文:[Ballons](https://developer.apple.com/swift/blog/?id=9)
|
本文由翻译自 Apple Swift Blog 的博文:[Ballons](https://developer.apple.com/swift/blog/?id=9)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Swift与C语言指针友好合作
|
# Swift 与 C 语言指针友好合作
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
> 翻译:[老码团队翻译组-Relly](http://weibo.com/penguinliong/)
|
> 翻译:[老码团队翻译组-Relly](http://weibo.com/penguinliong/)
|
||||||
@ -11,16 +11,16 @@
|
|||||||
- [用作字符串参数的指针](#string-as-para-pointer)
|
- [用作字符串参数的指针](#string-as-para-pointer)
|
||||||
- [指针参数转换的安全性](#security-of-pointer-cast)
|
- [指针参数转换的安全性](#security-of-pointer-cast)
|
||||||
|
|
||||||
Objective-C和C的API常常会需要用到指针。Swift中的数据类型都原生支持基于指针的Cocoa API,不仅如此,Swift会自动处理部分最常用的将指针作为参数传递的情况。这篇文章中,我们将着眼于在Swift中让C语言指针与变量、数组和字符串共同工作。
|
Objective-C 和 C 的 API 常常会需要用到指针。Swift 中的数据类型都原生支持基于指针的 Cocoa API,不仅如此,Swift 会自动处理部分最常用的将指针作为参数传递的情况。这篇文章中,我们将着眼于在 Swift 中让 C 语言指针与变量、数组和字符串共同工作。
|
||||||
|
|
||||||
####用以输入/输出的参数指针
|
####用以输入/输出的参数指针
|
||||||
|
|
||||||
C和Objective-C并不支持多返回值,所以Cocoa API中常常将指针作为一种在方法间传递额外数据的方式。Swift允许指针被当作`inout`参数使用,所以你可以用符号`&`将对一个变量的引用作为指针参数传递。举例来说:`UIColor`中的`getRed(_:green:blue:alpha:)`方法需要四个`CGFloat*`指针来接收颜色的组成信息,我们使用`&`来将这些组成信息捕获为本地变量:
|
C 和 Objective-C 并不支持多返回值,所以 Cocoa API 中常常将指针作为一种在方法间传递额外数据的方式。Swift 允许指针被当作 `inout` 参数使用,所以你可以用符号 `&` 将对一个变量的引用作为指针参数传递。举例来说:`UIColor` 中的 `getRed(_:green:blue:alpha:)` 方法需要四个 `CGFloat*` 指针来接收颜色的组成信息,我们使用 `&` 来将这些组成信息捕获为本地变量:
|
||||||
```swift
|
```swift
|
||||||
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
|
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
|
||||||
color.getRed(&r, green: &g, blue: &b, alpha: &a)
|
color.getRed(&r, green: &g, blue: &b, alpha: &a)
|
||||||
```
|
```
|
||||||
另一种常见的情况是Cocoa中`NSError`的习惯用法。许多方法会使用一个`NSError**`参数来储存可能的错误的信息。举例来说:我们用`NSFileManager`的`contentOfDirectoryAtPath(_:error:)`方法来将目录下的内容列表,并将潜在的错误指向一个`NSError?`变量:
|
另一种常见的情况是 Cocoa 中 `NSError` 的习惯用法。许多方法会使用一个 `NSError**` 参数来储存可能的错误的信息。举例来说:我们用 `NSFileManager` 的 `contentOfDirectoryAtPath(_:error:)` 方法来将目录下的内容列表,并将潜在的错误指向一个 `NSError?` 变量:
|
||||||
```swift
|
```swift
|
||||||
var maybeError: NSError?
|
var maybeError: NSError?
|
||||||
if let contents = NSFileManager.defaultManager()
|
if let contents = NSFileManager.defaultManager()
|
||||||
@ -30,11 +30,11 @@ if let contents = NSFileManager.defaultManager()
|
|||||||
// Handle the error
|
// Handle the error
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
为了安全性,Swift要求被使用`&`传递的变量已经初始化。因为无法确定这个方法会不会在写入数据前尝试从指针中读取数据。
|
为了安全性,Swift 要求被使用 `&` 传递的变量已经初始化。因为无法确定这个方法会不会在写入数据前尝试从指针中读取数据。
|
||||||
|
|
||||||
####作为数组使用的参数指针
|
####作为数组使用的参数指针
|
||||||
|
|
||||||
在C语言中,数组和指针的联系十分紧密,而Swift允许数组能够作为指针使用,从而与基于数组的C语言API协同工作更加简单。一个固定的数组可以使用一个常量指针直接传递,一个变化的数组可以用`&`运算符将一个非常量指针传递。就和输入/输出参数指针一样。举例来说:我们可以用Accelerate框架中的`vDSP_vadd`方法让两个数组`a`和`b`相加,并将结果写入第三个数组`result`。
|
在 C 语言中,数组和指针的联系十分紧密,而 Swift 允许数组能够作为指针使用,从而与基于数组的 C 语言 API 协同工作更加简单。一个固定的数组可以使用一个常量指针直接传递,一个变化的数组可以用 `&` 运算符将一个非常量指针传递。就和输入/输出参数指针一样。举例来说:我们可以用 Accelerate 框架中的 `vDSP_vadd` 方法让两个数组 `a` 和 `b` 相加,并将结果写入第三个数组 `result`。
|
||||||
```swift
|
```swift
|
||||||
import Accelerate
|
import Accelerate
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ vDSP_vadd(a, 1, b, 1, &result, 1, 4)
|
|||||||
|
|
||||||
## 用作字符串参数的指针
|
## 用作字符串参数的指针
|
||||||
|
|
||||||
C语言中用`cont char*`指针来作为传递字符串的基本方式。Swift中的`String`可以被当作一个无限长度UTF-8编码的`const char*`指针来传递给方法。举例来说:我们可以直接传递一个字符串给一个标准C和POSIX库方法
|
C 语言中用 `cont char*` 指针来作为传递字符串的基本方式。Swift 中的 `String` 可以被当作一个无限长度 UTF-8编码的 `const char*` 指针来传递给方法。举例来说:我们可以直接传递一个字符串给一个标准 C 和 POSIX 库方法
|
||||||
```swift
|
```swift
|
||||||
puts("Hello from libc")
|
puts("Hello from libc")
|
||||||
let fd = open("/tmp/scratch.txt", O_WRONLY|O_CREAT, 0o666)
|
let fd = open("/tmp/scratch.txt", O_WRONLY|O_CREAT, 0o666)
|
||||||
@ -65,9 +65,9 @@ if fd < 0 {
|
|||||||
|
|
||||||
## 指针参数转换的安全性
|
## 指针参数转换的安全性
|
||||||
|
|
||||||
Swift很努力地使与C语言指针的交互更加便利,因为它们广泛地存在于Cocoa之中,同时保持一定的安全性。然而,相比你的其他Swift代码与C语言的指针交互具有潜在的不安全性,所以务必要小心使用。其中特别要注意:
|
Swift 很努力地使与 C 语言指针的交互更加便利,因为它们广泛地存在于 Cocoa 之中,同时保持一定的安全性。然而,相比你的其他 Swift 代码与 C 语言的指针交互具有潜在的不安全性,所以务必要小心使用。其中特别要注意:
|
||||||
- 如果被调用者为了在其返回值之后再次使用而保存了C指针的数据,那么这些转换使用起来并不安全。转换后的指针仅在调用期间保证有效。甚至你将同样的变量、数组或字符串作为多指针参数再次传递,你每次都会收到一个不同的指针。这个异常将全局或静态地储存为变量。你可以安全地将这段地址当作永久唯一的指针使用。例如:作为一个KVO上下文参数使用的时候。
|
- 如果被调用者为了在其返回值之后再次使用而保存了 C 指针的数据,那么这些转换使用起来并不安全。转换后的指针仅在调用期间保证有效。甚至你将同样的变量、数组或字符串作为多指针参数再次传递,你每次都会收到一个不同的指针。这个异常将全局或静态地储存为变量。你可以安全地将这段地址当作永久唯一的指针使用。例如:作为一个 KVO 上下文参数使用的时候。
|
||||||
|
|
||||||
- 当指针类型为`Array`或`String`时,溢出检查不是强制进行的。 基于C语言的API无法增加数组和字符串大小,所以在你将其传递到基于C语言的API之前,你必须确保数组或字符的大小正确。
|
- 当指针类型为 `Array` 或 `String` 时,溢出检查不是强制进行的。 基于 C 语言的 API 无法增加数组和字符串大小,所以在你将其传递到基于 C 语言的 API 之前,你必须确保数组或字符的大小正确。
|
||||||
|
|
||||||
如果你需要使用基于指针的API时没有遵守以上指导,或是你重写了接受指针参数的Cocoa方法,于是你可以在Swift中直接用不安全的指针来使用未经处理的内存。在未来的文章中我们将着眼于更加高级的情况。
|
如果你需要使用基于指针的 API 时没有遵守以上指导,或是你重写了接受指针参数的 Cocoa 方法,于是你可以在 Swift 中直接用不安全的指针来使用未经处理的内存。在未来的文章中我们将着眼于更加高级的情况。
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Swift里的值类型与引用类型
|
# Swift 里的值类型与引用类型
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
> 翻译:[老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
> 翻译:[老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
||||||
@ -10,10 +10,10 @@
|
|||||||
- [Mutation(修改)在安全中扮演的角色](#act-in=mutation)
|
- [Mutation(修改)在安全中扮演的角色](#act-in=mutation)
|
||||||
- [如何选择类型](#how-to-choose)
|
- [如何选择类型](#how-to-choose)
|
||||||
|
|
||||||
### Swift里面的类型分为两种:
|
### Swift 里面的类型分为两种:
|
||||||
|
|
||||||
* **值类型(Value Types)**:每个实例都保留了一分独有的数据拷贝,一般以结构体 `(struct)`、`枚举(enum)` 或者`元组(tuple)`的形式出现。
|
* **值类型(Value Types)**:每个实例都保留了一分独有的数据拷贝,一般以结构体 `(struct)`、` 枚举(enum)` 或者 `元组(tuple)`的形式出现。
|
||||||
* **引用类型(Reference Type)**:每个实例共享同一份数据来源,一般以`类(class)`的形式出现。
|
* **引用类型(Reference Type)**:每个实例共享同一份数据来源,一般以 `类(class)`的形式出现。
|
||||||
|
|
||||||
在这篇博文里面,我们会介绍两种类型各自的优点,以及应该怎么选择使用。
|
在这篇博文里面,我们会介绍两种类型各自的优点,以及应该怎么选择使用。
|
||||||
|
|
||||||
@ -26,8 +26,8 @@
|
|||||||
// 下面是一个值类型的例子
|
// 下面是一个值类型的例子
|
||||||
struct S { var data: Int = -1 }
|
struct S { var data: Int = -1 }
|
||||||
var a = S()
|
var a = S()
|
||||||
var b = a // b是a的拷贝
|
var b = a // b 是 a 的拷贝
|
||||||
a.data = 42 // 更改a的数据,b的不受影响
|
a.data = 42 // 更改 a 的数据,b 的不受影响
|
||||||
println("\(a.data), \(b.data)") // 输出结果 "42, -1"
|
println("\(a.data), \(b.data)") // 输出结果 "42, -1"
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -39,24 +39,24 @@
|
|||||||
// 下面是一个引用类型的例子
|
// 下面是一个引用类型的例子
|
||||||
class C { var data: Int = -1 }
|
class C { var data: Int = -1 }
|
||||||
var x = C()
|
var x = C()
|
||||||
var y = x // y是x的拷贝
|
var y = x // y 是 x 的拷贝
|
||||||
x.data = 42 // 更改x的数据,等于同时修改了y
|
x.data = 42 // 更改 x 的数据,等于同时修改了 y
|
||||||
println("\(x.data), \(y.data)") // 输出结果 "42, 42"
|
println("\(x.data), \(y.data)") // 输出结果 "42, 42"
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="act-in=mutation"></a>
|
<a name="act-in=mutation"></a>
|
||||||
#### Mutation(修改)在安全中扮演的角色
|
#### Mutation(修改)在安全中扮演的角色
|
||||||
|
|
||||||
值类型较引用类型来说,会让你更容易在大量代码中理清状况。如果你总是得到一个独立的拷贝出来的实例,你就可以放心它不会被你app里面的其他部分代码默默地修改。这在多线程的环境里面是尤为重要的,因为另外一个线程可能会在暗地里修改你的数据。因此可能会造成严重的程序错误,这在调试过程中非常难以排除。
|
值类型较引用类型来说,会让你更容易在大量代码中理清状况。如果你总是得到一个独立的拷贝出来的实例,你就可以放心它不会被你 app 里面的其他部分代码默默地修改。这在多线程的环境里面是尤为重要的,因为另外一个线程可能会在暗地里修改你的数据。因此可能会造成严重的程序错误,这在调试过程中非常难以排除。
|
||||||
|
|
||||||
由于差别主要在于修改数据的后果,那么当实例的数据只读,不存在需要更改的情况下,用哪种类型都是没有分别的。
|
由于差别主要在于修改数据的后果,那么当实例的数据只读,不存在需要更改的情况下,用哪种类型都是没有分别的。
|
||||||
|
|
||||||
你可能在想,有的时候我可能也需要一个完全不变的类。这样使用`Cocoa NSObject`对象的时候会比较容易,又可以保留值语义的好处。在今天,你可以通过只使用不可变的存储属性,和避开任何可以修改状态的API,用Swift写出一个不可变类`(immutable class)`。实际上,很多基本的Cocoa类,例如`NSURL`,都是设计成不可变类的。然而,Swift语言目前只强制`struct`和`enum`这种值类型的不可变性,对类这种引用类型则没有。(例如还不支持强制将子类的限制为不可变类)
|
你可能在想,有的时候我可能也需要一个完全不变的类。这样使用 `Cocoa NSObject` 对象的时候会比较容易,又可以保留值语义的好处。在今天,你可以通过只使用不可变的存储属性,和避开任何可以修改状态的 API,用 Swift 写出一个不可变类 `(immutable class)`。实际上,很多基本的 Cocoa 类,例如 `NSURL`,都是设计成不可变类的。然而,Swift 语言目前只强制 `struct` 和 `enum` 这种值类型的不可变性,对类这种引用类型则没有。(例如还不支持强制将子类的限制为不可变类)
|
||||||
|
|
||||||
<a name="how-to-choose"></a>
|
<a name="how-to-choose"></a>
|
||||||
#### 如何选择类型?
|
#### 如何选择类型?
|
||||||
|
|
||||||
所以当我们想要建立一个新的类型的时候,怎么决定用值类型还是引用类型呢?当你使用Cocoa框架的时候,很多API都要通过NSObject的子类使用,所以这时候必须要用到引用类型class。在其他情况下,有下面几个准则:
|
所以当我们想要建立一个新的类型的时候,怎么决定用值类型还是引用类型呢?当你使用 Cocoa 框架的时候,很多 API 都要通过 NSObject 的子类使用,所以这时候必须要用到引用类型 class。在其他情况下,有下面几个准则:
|
||||||
|
|
||||||
* **什么时候该用值类型**:
|
* **什么时候该用值类型**:
|
||||||
* 要用==运算符来比较实例的数据时
|
* 要用==运算符来比较实例的数据时
|
||||||
@ -67,9 +67,9 @@
|
|||||||
* 要用==运算符来比较实例身份的时候
|
* 要用==运算符来比较实例身份的时候
|
||||||
* 你希望有创建一个共享的、可变对象的时候
|
* 你希望有创建一个共享的、可变对象的时候
|
||||||
|
|
||||||
在Swift里面,数组(Array)、字符串(String)、字典(Dictionary)都属于值类型。它们就像C语言里面简单的int值,是一个个独立的数据个体。你不需要花任何功夫来防范其他代码在暗地里修改它们。更重要的是,你可以在线程之间安全的传递变量,而不需要特地去同步。在Swift高安全性的精神下,这个模式会帮助你用Swift写出更可控的代码。
|
在 Swift 里面,数组(Array)、字符串(String)、字典(Dictionary)都属于值类型。它们就像 C 语言里面简单的 int 值,是一个个独立的数据个体。你不需要花任何功夫来防范其他代码在暗地里修改它们。更重要的是,你可以在线程之间安全的传递变量,而不需要特地去同步。在 Swift 高安全性的精神下,这个模式会帮助你用 Swift 写出更可控的代码。
|
||||||
|
|
||||||
-----------------
|
-----------------
|
||||||
本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
||||||
|
|
||||||
##### 本文由翻译自Apple Swift Blog :[Value and Reference Types](https://developer.apple.com/swift/blog/?id=10)
|
##### 本文由翻译自 Apple Swift Blog :[Value and Reference Types](https://developer.apple.com/swift/blog/?id=10)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# 访问控制和protected
|
# 访问控制和 protected
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
> 翻译:[老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
> 翻译:[老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
||||||
@ -8,26 +8,26 @@
|
|||||||
|
|
||||||
很多其他编程语言都有一种”protected“设定,可以限制某些类方法只能被它的子类所使用。
|
很多其他编程语言都有一种”protected“设定,可以限制某些类方法只能被它的子类所使用。
|
||||||
|
|
||||||
Swift支持了访问控制后,大家给我们的反馈都很不错。而有的开发者问我们:“为什么Swift没有类似protected的选项?”
|
Swift 支持了访问控制后,大家给我们的反馈都很不错。而有的开发者问我们:“为什么 Swift 没有类似 protected 的选项?”
|
||||||
|
|
||||||
**当我们在设计Swift访问控制的不同等级时,我们认为有两种主要场景:**
|
**当我们在设计 Swift 访问控制的不同等级时,我们认为有两种主要场景:**
|
||||||
|
|
||||||
* 在一个APP里:隐藏某个类的私密细节。
|
* 在一个 APP 里:隐藏某个类的私密细节。
|
||||||
* 在一个开源框架里:不让导入这个框架的APP,随便接触框架的内部实现细节。
|
* 在一个开源框架里:不让导入这个框架的 APP,随便接触框架的内部实现细节。
|
||||||
|
|
||||||
上面的两种常见情况,对应着private和internal这两个等级。
|
上面的两种常见情况,对应着 private 和 internal 这两个等级。
|
||||||
|
|
||||||
而protected相当于把访问控制和继承特性混在一起,把访问控制的等级设定增加了一个维度,使之复杂化。即使设定了protected,子类还是可以通过新的公开方法、新的属性来接触到所谓“protected”了的API。另一方面,我们可以在各种地方重写一个方法,所谓的保护却没有提供优化机制。这种设定往往在做不必要的限制 一 protected允许了子类,但又禁止所有其他别的类(包括那些帮助子类实现某些功能的类)接触父类的成员。
|
而 protected 相当于把访问控制和继承特性混在一起,把访问控制的等级设定增加了一个维度,使之复杂化。即使设定了 protected,子类还是可以通过新的公开方法、新的属性来接触到所谓“protected”了的 API。另一方面,我们可以在各种地方重写一个方法,所谓的保护却没有提供优化机制。这种设定往往在做不必要的限制 一 protected 允许了子类,但又禁止所有其他别的类(包括那些帮助子类实现某些功能的类)接触父类的成员。
|
||||||
|
|
||||||
有的开发者指出,apple的框架有时候也会把给子类用的API分隔出来。这时候protected不就有用了吗?我们研究后发现,这些方法一般属于下面两种情况:一是这些方法对子类以外的类没啥用,所以不需要严格保护(例如上面说的协助实现某些功能的类)。二是这些方法就是设计出来被重写,而不是直接用的。举个例子,`drawRect(_:) `就是在UIKit基础上使用的方法,但它不能在UIKit以外应用。
|
有的开发者指出,apple 的框架有时候也会把给子类用的 API 分隔出来。这时候 protected 不就有用了吗?我们研究后发现,这些方法一般属于下面两种情况:一是这些方法对子类以外的类没啥用,所以不需要严格保护(例如上面说的协助实现某些功能的类)。二是这些方法就是设计出来被重写,而不是直接用的。举个例子,`drawRect(_:)` 就是在 UIKit 基础上使用的方法,但它不能在 UIKit 以外应用。
|
||||||
|
|
||||||
除此之外,如果有了protected,它要怎么样和extension相互作用呢?一个类的extension能接触它的protected成员吗?一个子类的extension可以接触父类的protected成员吗?extension声明的位置对访问控制等级有没有影响呢?(复杂到要哭了是不是?)
|
除此之外,如果有了 protected,它要怎么样和 extension 相互作用呢?一个类的 extension 能接触它的 protected 成员吗?一个子类的 extension 可以接触父类的 protected 成员吗?extension 声明的位置对访问控制等级有没有影响呢?(复杂到要哭了是不是?)
|
||||||
|
|
||||||
对访问控制的设计,也依循了Objective-C开发者(包括apple内外的)的常规做法。Objective-C方法和属性一般在.h头文件里声明,但也可以写在.m实现文件里。假如有一个公开的类,想把里面某些部分设为只有框架内可以获取时,开发者一般会创建另一个头文件给内部使用。以上三种访问级别,就对应了Swift里面的public,private和internal。
|
对访问控制的设计,也依循了 Objective-C 开发者(包括 apple 内外的)的常规做法。Objective-C 方法和属性一般在.h 头文件里声明,但也可以写在.m 实现文件里。假如有一个公开的类,想把里面某些部分设为只有框架内可以获取时,开发者一般会创建另一个头文件给内部使用。以上三种访问级别,就对应了 Swift 里面的 public,private 和 internal。
|
||||||
|
|
||||||
Swift的访问控制等级和继承无关,是单维度、非常清楚明了的。我们认为这样的模式更简洁,同时满足了最主要的需求:将一个类、或一个框架的实现细节隔离保护起来。这可能和你以前用过的不同,但我们鼓励你试试看。
|
Swift 的访问控制等级和继承无关,是单维度、非常清楚明了的。我们认为这样的模式更简洁,同时满足了最主要的需求:将一个类、或一个框架的实现细节隔离保护起来。这可能和你以前用过的不同,但我们鼓励你试试看。
|
||||||
|
|
||||||
-----------------
|
-----------------
|
||||||
本章节不是老码的原创,是老码认真的阅读了苹果的官方博客,自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌。还是看不懂?请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
本章节不是老码的原创,是老码认真的阅读了苹果的官方博客,自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌。还是看不懂?请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
||||||
|
|
||||||
##### 本文由翻译自Apple Swift Blog :[Access Control and Protected](原文地址:https://developer.apple.com/swift/blog/?id=11)
|
##### 本文由翻译自 Apple Swift Blog :[Access Control and Protected](原文地址:https://developer.apple.com/swift/blog/?id=11)
|
||||||
|
|||||||
@ -6,19 +6,19 @@
|
|||||||
|
|
||||||
本页包含内容:
|
本页包含内容:
|
||||||
|
|
||||||
- [为Dictionary增加objectsForKeys函数](#add-function)
|
- [为 Dictionary 增加 objectsForKeys 函数](#add-function)
|
||||||
- [Swift中更简便的方法](##easy-function)
|
- [Swift 中更简便的方法](##easy-function)
|
||||||
- [内嵌可选类型](#nested-optional)
|
- [内嵌可选类型](#nested-optional)
|
||||||
- [提供一个默认值](#provide-default)
|
- [提供一个默认值](#provide-default)
|
||||||
|
|
||||||
可选类型是Swift中新引入的,功能很强大。在这篇博文里讨论的,是在Swift里,如何通过可选类型来保证强类型的安全性。作为例子,我们来创建一个Objective-C API的Swift版本,但实际上Swift本身并不需要这样的API。
|
可选类型是 Swift 中新引入的,功能很强大。在这篇博文里讨论的,是在 Swift 里,如何通过可选类型来保证强类型的安全性。作为例子,我们来创建一个 Objective-C API 的 Swift 版本,但实际上 Swift 本身并不需要这样的 API。
|
||||||
|
|
||||||
<a name="#add-function"></a>
|
<a name="#add-function"></a>
|
||||||
#### 为Dictionary增加objectsForKeys函数
|
#### 为 Dictionary 增加 objectsForKeys 函数
|
||||||
|
|
||||||
在Objective-C中,```NSDictionary```有一个方法```-objectsForKeys:NoFoundMarker:```, 这个方法需要一个```NSArray```数组作为键值参数,然后返回一个包含相关值的数组。文档里写到:"返回数组中的第N个值,和输入数组中的第N个值相对应",那如果有某个键值在字典里不存在呢?于是就有了```notFoundMarker```作为返回提示。比如第三个键值没有找到,那么在返回数组中第三个值就是这个```notFoundMarker```,而不是字典中的第三个值,但是这个值只是用来提醒原字典中没有找到对应值,但在返回数组中该元素存在,且用```notFoundMarker```作为占位符,因为这个对象不能直接使用,所以在Foundation框架中有个专门的类处理这个情况:```NSNull```。
|
在 Objective-C 中,```NSDictionary```有一个方法```-objectsForKeys:NoFoundMarker:```, 这个方法需要一个```NSArray```数组作为键值参数,然后返回一个包含相关值的数组。文档里写到:"返回数组中的第 N 个值,和输入数组中的第 N 个值相对应",那如果有某个键值在字典里不存在呢?于是就有了```notFoundMarker```作为返回提示。比如第三个键值没有找到,那么在返回数组中第三个值就是这个```notFoundMarker```,而不是字典中的第三个值,但是这个值只是用来提醒原字典中没有找到对应值,但在返回数组中该元素存在,且用```notFoundMarker```作为占位符,因为这个对象不能直接使用,所以在 Foundation 框架中有个专门的类处理这个情况:```NSNull```。
|
||||||
|
|
||||||
在Swift中,```Dictionary```类没有类似```objectsForKeys```的函数,为了说明问题,我们动手加一个,并且使其成为操作字典值的通用方法。我们可以用```extension```来实现:
|
在 Swift 中,```Dictionary```类没有类似```objectsForKeys```的函数,为了说明问题,我们动手加一个,并且使其成为操作字典值的通用方法。我们可以用```extension```来实现:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
extension Dictionary{
|
extension Dictionary{
|
||||||
@ -28,7 +28,7 @@ extension Dictionary{
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
以上就是我们实现的Swift版本,这个和Objective-C版本有很大区别。在Swift中,因为其强类型的原因限制了返回的结果数组只能包含单一类型的元素,所以我们不能放```NSNull```在字符串数组中,但是,Swift有更好的选择,我们可以返回一个可选类型数据。我们所有的值都封包在可选类型中,而不是```NSNull```, 我们只用```nil```就可以了。
|
以上就是我们实现的 Swift 版本,这个和 Objective-C 版本有很大区别。在 Swift 中,因为其强类型的原因限制了返回的结果数组只能包含单一类型的元素,所以我们不能放```NSNull```在字符串数组中,但是,Swift 有更好的选择,我们可以返回一个可选类型数据。我们所有的值都封包在可选类型中,而不是```NSNull```, 我们只用```nil```就可以了。
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
extension Dictionary{
|
extension Dictionary{
|
||||||
@ -44,9 +44,9 @@ extension Dictionary{
|
|||||||
```
|
```
|
||||||
|
|
||||||
<a name="#easy-function"></a>
|
<a name="#easy-function"></a>
|
||||||
#### Swift中更简便的方法
|
#### Swift 中更简便的方法
|
||||||
|
|
||||||
小伙伴们可能会问,为什么Swift中不需要实现这么一个API呢?其实其有更简单的实现,如下面代码所示:
|
小伙伴们可能会问,为什么 Swift 中不需要实现这么一个 API 呢?其实其有更简单的实现,如下面代码所示:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
extension Dictionary {
|
extension Dictionary {
|
||||||
@ -56,7 +56,7 @@ extension Dictionary {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
上述方式实现的功能和最开始的方法实现的功能相同,虽然核心的功能是封装了```map```的调用,这个例子也说明了为什么Swift没有提供轻量级的API接口,因为小伙伴们简单的调用```map```就可以实现。
|
上述方式实现的功能和最开始的方法实现的功能相同,虽然核心的功能是封装了```map```的调用,这个例子也说明了为什么 Swift 没有提供轻量级的 API 接口,因为小伙伴们简单的调用```map```就可以实现。
|
||||||
|
|
||||||
接下来,我们实验几个例子:
|
接下来,我们实验几个例子:
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ var last:T? { get }
|
|||||||
|
|
||||||
很明显```last```属性的类型是数组元素类型的可选类型,这种情况下,因为元素类型是```(String?)```,那么再结合返回的类型,于是其结果就是```String??```了,这就是所谓的嵌套可选类型。但嵌套可选类型本质是什么意思呢?
|
很明显```last```属性的类型是数组元素类型的可选类型,这种情况下,因为元素类型是```(String?)```,那么再结合返回的类型,于是其结果就是```String??```了,这就是所谓的嵌套可选类型。但嵌套可选类型本质是什么意思呢?
|
||||||
|
|
||||||
如果在Objective-C中重新调用上述方法,我们将使用```NSNull```作为占位符,Objective-C的调用语法如下所示:
|
如果在 Objective-C 中重新调用上述方法,我们将使用```NSNull```作为占位符,Objective-C 的调用语法如下所示:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
[dict valuesForKeys:@[@"1", @"4"] notFoundMarker:[NSNull null]].lastObject
|
[dict valuesForKeys:@[@"1", @"4"] notFoundMarker:[NSNull null]].lastObject
|
||||||
@ -113,7 +113,7 @@ var last:T? { get }
|
|||||||
// nil
|
// nil
|
||||||
```
|
```
|
||||||
|
|
||||||
不管是Swift版本还是Objective-C版本,返回值为```nil```都意味数组是空的,所以它就没有最后一个元素。 但是如果返回是```Optional(nil)```或者Objective-C中的```NSNull```都表示数组中的最后一个元素存在,但是元素的内容是空的。在Objective-C中只能借助```NSNull```作为占位符来达到这个目的,但是Swift却可以语言系统类型的角度的实现。
|
不管是 Swift 版本还是 Objective-C 版本,返回值为```nil```都意味数组是空的,所以它就没有最后一个元素。 但是如果返回是```Optional(nil)```或者 Objective-C 中的```NSNull```都表示数组中的最后一个元素存在,但是元素的内容是空的。在 Objective-C 中只能借助```NSNull```作为占位符来达到这个目的,但是 Swift 却可以语言系统类型的角度的实现。
|
||||||
|
|
||||||
<a name="#provide-default"></a>
|
<a name="#provide-default"></a>
|
||||||
#### 提供一个默认值
|
#### 提供一个默认值
|
||||||
@ -132,9 +132,9 @@ extension Dictionary {
|
|||||||
dict.valuesForKeys(["1", "5"], notFoundMarker: "Anonymous")
|
dict.valuesForKeys(["1", "5"], notFoundMarker: "Anonymous")
|
||||||
```
|
```
|
||||||
|
|
||||||
和Objective-C相比,其需要占位符来达到占位的目的,但是Swift却已经从语言类型系统的层面原生的支持了这种用法,同时提供了丰富的语法功能。这就是Swift可选类型的强大之处。同时注意上述例子中用到了空合运算符```??```。
|
和 Objective-C 相比,其需要占位符来达到占位的目的,但是 Swift 却已经从语言类型系统的层面原生的支持了这种用法,同时提供了丰富的语法功能。这就是 Swift 可选类型的强大之处。同时注意上述例子中用到了空合运算符```??```。
|
||||||
|
|
||||||
-----------------
|
-----------------
|
||||||
本章节不是老码的原创,是老码认真的阅读了苹果的官方博客,自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌。还是看不懂?请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
本章节不是老码的原创,是老码认真的阅读了苹果的官方博客,自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌。还是看不懂?请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
||||||
|
|
||||||
##### 本文由翻译自Apple Swift Blog :[Optionals Case Study: valuesForKeys](https://developer.apple.com/swift/blog/?id=12)
|
##### 本文由翻译自 Apple Swift Blog :[Optionals Case Study: valuesForKeys](https://developer.apple.com/swift/blog/?id=12)
|
||||||
|
|||||||
@ -2,29 +2,29 @@
|
|||||||
> [Swift 开发者社区](http://swiftist.org)
|
> [Swift 开发者社区](http://swiftist.org)
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
> 如果你觉得这个项目不错,请[点击Star一下](https://github.com/numbbbbb/the-swift-programming-language-in-chinese),您的支持是我们最大的动力。
|
> 如果你觉得这个项目不错,请[点击 Star 一下](https://github.com/numbbbbb/the-swift-programming-language-in-chinese),您的支持是我们最大的动力。
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
> 关于文档中翻译错误,逻辑错误以及疑难问题答疑,请关注["@老码团队"](http://weibo.com/u/5241713117
|
> 关于文档中翻译错误,逻辑错误以及疑难问题答疑,请关注["@老码团队"](http://weibo.com/u/5241713117
|
||||||
)官方微博,会有技术人员统一收集答疑
|
)官方微博,会有技术人员统一收集答疑
|
||||||
|
|
||||||
# The Swift Programming Language 中文版####
|
# The Swift Programming Language 中文版
|
||||||
|
|
||||||
###这一次,让中国和世界同步
|
###这一次,让中国和世界同步
|
||||||
|
|
||||||
现在是6月12日凌晨4:38,我用了整整一晚上的时间来进行最后的校对,终于可以在12日拿出一个可以发布的版本。
|
现在是6月12日凌晨4:38,我用了整整一晚上的时间来进行最后的校对,终于可以在12日拿出一个可以发布的版本。
|
||||||
|
|
||||||
9天时间,1317个 Star,310个 Fork,超过30人参与翻译和校对工作,项目最高排名GitHub总榜第4。
|
9天时间,1317个 Star,310个 Fork,超过30人参与翻译和校对工作,项目最高排名 GitHub 总榜第4。
|
||||||
|
|
||||||
设想过很多遍校对完成时的场景,仰天大笑还是泪流满面?真正到了这一刻才发现,疲倦已经不允许我有任何情绪。
|
设想过很多遍校对完成时的场景,仰天大笑还是泪流满面?真正到了这一刻才发现,疲倦已经不允许我有任何情绪。
|
||||||
|
|
||||||
说实话,刚开始发起项目的时候完全没想到会发展成今天这样,我一度计划自己一个人翻译完整本书。万万没想到,会有这么多的人愿意加入并贡献出自己的力量。
|
说实话,刚开始发起项目的时候完全没想到会发展成今天这样,我一度计划自己一个人翻译完整本书。万万没想到,会有这么多的人愿意加入并贡献出自己的力量。
|
||||||
|
|
||||||
coverxit发给我最后一份文档的时候说,我要去背单词了,我问他,周末要考六级?他说是的。
|
coverxit 发给我最后一份文档的时候说,我要去背单词了,我问他,周末要考六级?他说是的。
|
||||||
|
|
||||||
pp-prog告诉我,这几天太累了,校对到一半睡着了,醒来又继续做。2点17分,发给我校对完成的文档。
|
pp-prog 告诉我,这几天太累了,校对到一半睡着了,醒来又继续做。2点17分,发给我校对完成的文档。
|
||||||
|
|
||||||
lifedim说他平时12点就会睡,1点47分,发给我校对后的文档。
|
lifedim 说他平时12点就会睡,1点47分,发给我校对后的文档。
|
||||||
|
|
||||||
团队里每个人都有自己的事情,上班、上学、创业,但是我们只用了9天就完成整本书的翻译。我不知道大家付出了多少,牺牲了多少,但是我知道,他们的付出必将被这些文字记录下来,即使再过10年,20年,依然熠熠生辉,永不被人遗忘。
|
团队里每个人都有自己的事情,上班、上学、创业,但是我们只用了9天就完成整本书的翻译。我不知道大家付出了多少,牺牲了多少,但是我知道,他们的付出必将被这些文字记录下来,即使再过10年,20年,依然熠熠生辉,永不被人遗忘。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user