140 Commits

Author SHA1 Message Date
5263437673 Merge branch 'gh-pages' into feature/Ch-Closures 2021-06-22 07:49:53 +08:00
82e719acdf feat:「参数名称缩写 」节第二段和第三段有更新 2021-06-22 07:49:05 +08:00
9b302e76cb feat: 新增对 for-in 的描述 (#1141) 2021-06-21 10:39:22 -05:00
9d8588726a Welcome to Swift - Version Compatibility (#1137)
* feat: 更新版本兼容性章节

* fix: 修复语句不顺的问题
2021-06-21 09:59:50 -05:00
59e95dc3a5 feat: 更新 swift tour 代码变更 (#1138) 2021-06-21 09:57:15 -05:00
bb4d0c7fcd eat: 更新代码示例 (#1140) 2021-06-21 09:57:01 -05:00
e0c37b748c Update README.md 2021-06-16 10:23:59 -05:00
bf18871349 Update README.md 2021-06-16 09:21:01 -05:00
13c47f495d Update 27_Advanced_Operators.md (#1110)
修正一处 typo:结核性 -> 结合性;及一处文字缺失。
2021-05-04 11:23:34 -05:00
6b38f6d7a7 Update 24_Automatic_Reference_Counting.md 2021-02-03 07:33:11 -06:00
262a06affd Update 01_The_Basics.md (#1106)
英文原文: almost any
原中文翻译: 任何的
正确翻译: 几乎所有的
2021-01-20 22:14:39 -06:00
558814b61d 修复一处错别字 (#1105)
"字句" 应为 "子句"
2021-01-11 06:55:34 -06:00
2408ee2066 修复运算符声明文档错误 (#1103)
* 修复运算符声明文档错误

* infix-operator-attributes修改为infix-operator-group
2021-01-08 22:02:32 -06:00
7725dfb9ad Update 22_Generics.md (#1099) 2020-12-07 07:09:08 -06:00
2e82e1621a Fix #1095 “会”的位置错误 (#1096) 2020-10-25 07:27:51 -05:00
f2999daf52 Update 01_The_Basics.md (#1090)
* Update 01_The_Basics.md

* Update 01_The_Basics.md

Co-authored-by: Jie Liang <lj925184928@gmail.com>
2020-10-05 08:37:33 -05:00
83500eba22 fix wrong links, fix #1086 2020-07-15 20:55:11 -05:00
be7dca4e18 Update 10_Properties.md 2020-07-15 11:00:24 -05:00
99453d1d4e GenericParametersAndArguments (#1084)
* chore: 增加新段落的翻译

* Update 09_Generic_Parameters_and_Arguments.md

Co-authored-by: wamaker <fangzhou@dxy.cn>
Co-authored-by: Jie Liang <lj925184928@gmail.com>
2020-07-09 07:52:48 -05:00
72cb5a61b8 Advanced_Operators Swift 5.3 beata (#1083) 2020-07-07 11:32:34 -05:00
c9d8b0be6d update Protocols.md (#1082)
Co-authored-by: dingtongzhou <dingtongzhou@bytedance.com>
2020-07-07 07:06:02 -05:00
9abdbd4e4a Merge pull request #1081 from Nemocdz/gh-pages
更新 epub
2020-07-06 12:07:53 +08:00
a6656c4221 update 5.3 beta version 2020-07-06 12:06:53 +08:00
b73ff1765c update 5.2 release version 2020-07-06 12:06:35 +08:00
528f2109de Merge pull request #1076 from Nemocdz/gh-pages
update Swift5.3 beta
2020-07-06 11:51:26 +08:00
bf8ac090d8 Merge pull request #1080 from Nemocdz/fix_typo
fix typo
2020-07-06 11:46:34 +08:00
e7d525781a fix typo 2020-07-06 11:43:53 +08:00
fee0c4a388 Update 07_Closures.md (#1079)
add translation
2020-07-05 22:11:37 -05:00
da42305134 fix typo 2020-07-06 10:23:41 +08:00
9a84b62fab fix typo 2020-07-06 10:23:22 +08:00
9683a0b82f review 2020-07-06 10:22:59 +08:00
a00bd5b888 Generics (#1078)
* chore: 增加新句子

* chore: 添加新的段落

* fix: fix typo
2020-07-05 08:16:41 -05:00
2fd7ccd829 summary_of_the_grammar Swift 5.3 beta 2020-07-01 21:47:43 +08:00
f5c85a2eed expressions Swift 5.3 beta 2020-07-01 21:46:15 +08:00
65f605fc00 Update to Swift 5.3 beta (#1077)
* Update 01_The_Basics to Swift 5.3 beta

* Update 10_Properties to Swift 5.3 beta
2020-06-30 08:09:57 -05:00
6f2488e19d statements Swift 5.3 beta 2020-06-30 21:02:28 +08:00
7f94b446ef lexical_structure Swift 5.3 beta 2020-06-30 17:36:27 +08:00
50c356dade update error_handling Swift5.3beta 2020-06-29 22:18:16 +08:00
aa77e5cdd6 basic_operators to Swift 5.3 beta 2020-06-28 23:01:40 +08:00
31a51ccace strings_and_characters to Swift 5.3 beta 2020-06-28 22:45:18 +08:00
4fff00bd5c version_compatibility to Swift 5.3 beta 2020-06-28 22:09:36 +08:00
e18e9c422a Merge pull request #1051 from Nemocdz/gh-pages
fix typo
2020-06-15 23:19:50 +08:00
ff8a9ca1a4 fix typo 2020-06-15 23:00:40 +08:00
51b864f711 Update 21_Protocols.md 2020-06-14 22:29:46 -05:00
67df77108c Merge pull request #1049 from Nemocdz/gh-pages
统一翻译
2020-05-30 23:35:36 +08:00
f7c9433bff 统一翻译 2020-05-30 23:31:27 +08:00
05e7dafe9e Update README.md 2020-05-09 08:17:58 -05:00
764753697c Update README.md 2020-05-06 22:15:16 -05:00
2aef26f66a Merge pull request #1044 from Nemocdz/gh-pages
翻译修改
2020-04-25 23:08:13 +08:00
dcc5837a53 update translation 2020-04-25 23:05:52 +08:00
d21f043b64 Update 20_Extensions.md (#1043)
修改翻译中的逻辑错误
2020-04-08 11:31:24 -05:00
52c81ff7b1 Update 06_Functions.md (#1042)
更正一个错误词语
2020-03-31 12:20:50 -05:00
2c5d4a51ff fix url 2020-02-17 22:44:43 +08:00
f47766a015 Update README.md 2020-02-15 23:03:09 -06:00
08e7cf1e63 Swift 5.2 新增内容的部分翻译 (#1036)
* Add translations of swift 5.2.

* Add translations of swift 5.2.

* Add translations of swift 5.2.

* Add translations of swift 5.2.

* Update 04_Expressions.md

* Refine translations

* Refine translations

* Update 07_Attributes.md

Co-authored-by: Jie Liang <lj925184928@gmail.com>
2020-02-15 23:02:01 -06:00
3d38eaa8a0 Merge pull request #1038 from Nemocdz/gh-pages
update Swift 5.2 beta
2020-02-15 18:23:33 +08:00
e91cdd5d29 Merge remote-tracking branch 'upstream/gh-pages' into gh-pages 2020-02-15 18:20:14 +08:00
ad085a8563 update history revision 2020-02-15 18:14:44 +08:00
39bf300bd4 update declaration.md in swift 5.2 (#1037) 2020-02-14 12:32:39 -06:00
77b1824d6b update Revision History 2020-02-08 14:07:45 +08:00
93c7fada67 Merge pull request #1035 from Nemocdz/gh-pages
update Swift 5.2 beta
2020-02-08 13:48:31 +08:00
72829a29b9 update Summary of the Grammar 2020-02-08 13:36:55 +08:00
9a2bc92a6b Revert "update Summary of the Grammar"
This reverts commit f333332ee6.
2020-02-08 13:31:38 +08:00
f333332ee6 update Summary of the Grammar 2020-02-08 13:11:13 +08:00
5bf3e735a5 update Statements 2020-02-08 13:09:14 +08:00
f82f40fd47 update Properties 2020-02-08 13:03:33 +08:00
b894831e80 update Version Compatibility 2020-02-08 12:55:00 +08:00
4ea6ea7d7a Merge pull request #1034 from Nemocdz/gh-pages
更新 Swift 5.2 beta epub
2020-02-08 01:56:21 +08:00
cc9f46c3dc add Swift 5.2 beta epub 2020-02-08 01:53:52 +08:00
c945edb4e5 Merge remote-tracking branch 'upstream/gh-pages' into gh-pages 2020-02-08 00:03:59 +08:00
7d2b949236 Update 02_Basic_Operators.md 2020-02-06 11:52:12 -06:00
f416e311eb Update 03_Strings_and_Characters.md (#1022)
* Update 03_Strings_and_Characters.md

* SubString -> Substring

* Fix StringProtocol documentation URL
2020-01-29 10:16:12 -06:00
e59b995eda Merge pull request #1021 from ElfSundae/patch-1
Fix anchor link
2020-01-27 22:41:21 +08:00
89aa08ab57 Fix anchor link 2020-01-27 13:16:35 +08:00
670cef47ed typo fix (#1018) 2019-11-18 19:58:08 -06:00
55001fd340 Update 10_Properties.md
增加代码块高亮
2019-11-11 21:36:27 +08:00
d54d3a6c78 Update contributors.md
更新贡献者
2019-11-11 21:23:55 +08:00
ec456eac27 Update README.md
更新至 Swift 5.1
2019-11-11 21:13:11 +08:00
d4f1442dc9 Update README.md
更新至 Swift 5.1 正式版
2019-11-11 21:09:26 +08:00
f6da2e83a6 Merge branch 'gh-pages' of github.com:SwiftGGTeam/the-swift-programming-language-in-chinese into gh-pages 2019-11-10 11:06:21 -06:00
c4f7fac162 Merge branch 'SunsetWan-gh-pages' into gh-pages 2019-11-10 11:06:10 -06:00
10ff6be465 Merge branch 'gh-pages' of https://github.com/SunsetWan/the-swift-programming-language-in-chinese into SunsetWan-gh-pages 2019-11-10 11:05:44 -06:00
028268e7a6 Refine the translation 2019-11-09 16:18:31 +08:00
b31fa0ef60 Merge remote-tracking branch 'upstream/gh-pages' into gh-pages 2019-11-06 09:41:55 +08:00
caa9beebee update Swift 5.1 (#1017) 2019-11-05 15:10:01 -06:00
1489d076e0 Update SUMMARY.md 2019-11-05 15:09:31 -06:00
9a48057873 update Swift 5.1 2019-11-05 21:14:41 +08:00
92c89aa4da Merge pull request #1016 from Nemocdz/gh-pages
格式更改
2019-11-05 20:35:01 +08:00
7220830354 格式更改 2019-11-05 20:34:10 +08:00
cb11ad439e Merge pull request #1015 from Nemocdz/gh-pages
update Swift 5.1
2019-11-05 19:36:42 +08:00
1f2ffa1668 update Swift 5.1 2019-11-05 19:34:56 +08:00
453266a7c1 Merge pull request #1014 from Nemocdz/gh-pages
update Swift 5.1
2019-11-05 12:35:50 +08:00
8e7dbad8a7 update Swift 5.1 2019-11-05 12:30:30 +08:00
e8ae235524 Merge pull request #1013 from Nemocdz/gh-pages
update Swift 5.1
2019-11-04 12:33:27 +08:00
e5e81b81d1 update Swift 5.1 2019-11-04 12:30:07 +08:00
f7b9eb5e1e Merge remote-tracking branch 'upstream/gh-pages' into gh-pages
# Conflicts:
#	source/02_language_guide/24_Automatic_Reference_Counting.md
#	source/03_language_reference/03_Types.md
2019-11-04 11:49:42 +08:00
663a21536b Merge pull request #1012 from Phenmod/a-swift-tour-5.1
03_a_swift_tour 修订
2019-11-04 10:55:27 +08:00
7a115a996a 修改 2019-11-04 10:53:16 +08:00
9988f57550 Refine translation 2019-11-02 22:49:14 +08:00
32fa806e77 Keep the style of the old README.md 2019-11-02 22:37:36 +08:00
273a7bdd3b 修改部分翻译 & 部分原文有改动需要重新翻译 2019-11-01 16:03:53 +08:00
3063f18a78 改进些小翻译和格式 2019-10-30 20:57:18 +08:00
1f0844bb36 赋新值或者传参时,类型可推定 2019-10-30 17:27:43 +08:00
8d0a87909e 少一段 2019-10-30 17:17:46 +08:00
dfd3383bd0 末尾引号开始列之后的内容缩进不会被删除 2019-10-30 17:02:03 +08:00
7656143f00 Finish translation of Property Wrappers Section 2019-10-27 17:02:31 +08:00
eeda1ed0ed update according to #1010 2019-10-26 08:03:14 -05:00
3434b008eb 修改 !== 为 != 运算符。 (#1009) 2019-10-21 08:45:37 -05:00
1704931ac4 Update Patterns (#1008)
* 修复文章排版问题

* 修复图片饮用链接失效问题

* 增加缺失的标点

* 初次修改

* 修改 链接文件格式

* style: 去除 pattern 中右边文字的斜体

* style: 去除 pattern 中右边文字的斜体

* style: 去除错误样式

* chore: 新增枚举用例模式的翻译
2019-10-20 08:52:20 -05:00
b0a9b63e1f Translation in progress 2019-10-20 16:52:28 +08:00
2b715ddb06 Merge pull request #1007 from tbchen/hotfix-links
修改为正确的超级链接
2019-10-16 22:48:57 +08:00
05be6d4ba7 修改为正确的超级链接 2019-10-16 14:20:14 +09:00
631a2cbe92 #987 Lexicalstructure (#1006)
* 04_Collection_Types 5.1初版

* 校对以后的更新

* 第二次校对以后的修正

* 初次5.1更改

* 装饰改为包装

* 校对以后的更改

* 二次校对

* 5.1更新

* 初次校对后的更改
2019-10-15 21:41:45 -05:00
5d3d15b836 Translation in progress 2019-10-12 00:23:08 +08:00
11aa5ab0d6 fix anchor name and link format 2019-10-10 17:55:30 -05:00
028a6aa795 修改文档名称及顺序,与官方文档保持一致 (#1005) 2019-10-10 14:00:57 -05:00
7ba5a56301 Translation in progress 2019-10-11 00:10:57 +08:00
4dcdd13e74 use english punctuation, ref #1004 2019-10-09 11:38:51 -05:00
8f53cc7d82 fix wrong translation, ref #1003 2019-10-09 11:36:24 -05:00
48373d7791 Translation in progress 2019-10-09 23:43:32 +08:00
603a40adb0 初步完成 #985 (#996)
* 04_Collection_Types 5.1初版

* 校对以后的更新

* 第二次校对以后的修正

* 初次5.1更改

* 装饰改为包装

* 校对以后的更改

* 二次校对
2019-10-08 22:53:57 -05:00
06e3e12621 Subscripts #984 更新 5.1 (#999)
* 04_Collection_Types 5.1初版

* 校对以后的更新

* 第二次校对以后的修正

* 初次5.1更改

* 装饰改为包装

* 校对以后的更改

* 5.1更新初次完成

* 还原Attributes相关更新,避免冲突

* 初次校对的更改
2019-10-08 14:32:30 -05:00
5392b093d2 修改空格 (#1001) 2019-10-01 17:04:22 -05:00
8b743fafe5 update Types 5.1 (#1000)
* update swift 5.1

* update post

* update swift 5.1
2019-10-01 08:14:17 -05:00
30db13bc1e Update README.md 2019-10-01 18:17:42 +08:00
d34aee47cd update swift 5.1 2019-10-01 18:14:33 +08:00
64f80c9cba update 25_Access_Control to 5.1 (#994)
* update 25_Access_Control to 5.1

* Update 25_Access_Control.md

* Update 25_Access_Control.md

修改语句不通顺的翻译。
2019-09-30 09:26:00 -05:00
db48920fa3 update ARC (#998)
* update swift 5.1

* update post
2019-09-29 22:30:36 -05:00
9284579c0b Update Swift 5.1 21_protocols (#997) 2019-09-29 22:29:32 -05:00
20f0cb7f81 update post 2019-09-30 00:40:09 +08:00
ca027e9132 update swift 5.1 2019-09-29 23:40:39 +08:00
6d6118e7a3 Update README.md 2019-09-28 22:26:58 -05:00
d1b4d709b6 Merge pull request #993 from Nemocdz/gh-pages
修改文档,更新 epub
2019-09-24 21:09:08 +08:00
0e784e110d feat: update document 2019-09-24 21:05:03 +08:00
7bd73172ed fix: duplicate 2019-09-24 21:03:29 +08:00
f3a4630915 Update 03_Strings_and_Characters.md (#978)
错别字修改
2019-08-22 11:03:02 -05:00
02e0b33fd6 Update 21_Protocols.md (#976) 2019-08-08 08:55:03 -05:00
38ba1198b7 修正示例代码 (#975) 2019-07-25 23:05:50 -05:00
eedcd69d28 Update 25_Access_Control.md (#974) 2019-07-23 23:35:29 -05:00
45c537a42f 修改翻译 2019-07-15 10:48:01 +08:00
64 changed files with 4860 additions and 4006 deletions

View File

@ -7,11 +7,12 @@
# 在线阅读
使用 GitBook 制作,可以直接 [在线阅读](https://swiftgg.gitbook.io/swift/)。
使用 GitBook 制作,可以 [GitBook](https://swiftgg.gitbook.io/swift/) 网站阅读
# 当前阶段
- 更新到 Swift 5.12019-07-10
- 更新到 Swift 5.22020-02-15
- 更新到 Swift 5.12019-11-11
- 更新到 Swift 5.02019-04-05
- 更新到 Swift 4.22019-01-29
- 更新到 Swift 4.12018-04-12感谢 [@Mylittleswift](https://github.com/Mylittleswift)
@ -57,8 +58,12 @@ diff 操作如下:
| 术语 | 备选翻译 |
| --- | --- |
| property wrapper | 属性包装器([翻译相关讨论](https://github.com/SwiftGGTeam/the-swift-programming-language-in-chinese/issues/982#issuecomment-536244784) |
| projected value | 被呈现值 |
| wrapped value | 被包装值 |
| argument | 实参 |
| parameter | 形参 |
| variadic parameters| 可变参数 |
| associated type | 关联类型 |
| range | 区间 |
| type property | 类型属性 |

Binary file not shown.

Binary file not shown.

View File

@ -2,7 +2,7 @@
Swift 是一种非常好的编写软件的方式,无论是手机,台式机,服务器,还是其他运行代码的设备。它是一种安全,快速和互动的编程语言,将现代编程语言的精华和苹果工程师文化的智慧,以及来自开源社区的多样化贡献结合了起来。编译器对性能进行了优化,编程语言对开发进行了优化,两者互不干扰,鱼与熊掌兼得。
Swift 对于初学者来说也很友好。它是第一个既满足工业标准又像脚本语言一样充满表现力和趣味的系统编程语言。它支持代码预览playgrounds这个革命性的特性可以允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。
Swift 对于初学者来说也很友好。它是一门满足工业标准的编程语言,但又有着脚本语言般的表达力和可玩性。它支持代码预览playgrounds这个革命性的特性可以允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。
Swift 通过采用现代编程模式来避免大量常见编程错误:

View File

@ -0,0 +1,13 @@
# 版本兼容性
本书描述的是在 Xcode 13 中默认包含的 Swift 5.5 版本。你可以使用 Xcode 13 来构建 Swift 5.5、Swift 4.2 或 Swift 4 写的项目。
使用 Xcode 13 构建 Swift 4 和 Swift 4.2 代码时Swift 5.5 的大多数功能都适用。但以下功能仅支持 Swift 5.5 或更高版本:
* 返回值是不透明类型的函数依赖 Swift 5.1 运行时。
* **try?** 表达式不会为已返回可选类型的代码引入额外的可选类型层级。
* 大数字的整型字面量初始化代码的类型将会被正确推导,例如 **UInt64(0xffff_ffff_ffff_ffff)** 将会被推导为整型类型而非溢出。
并发特性需要 Swift 5.5 及以上版本,以及一个提供了并发相关类型的 Swift 标准库版本。要应用于苹果平台,请至少将部署版本设置为 iOS 15、macOS 12、tvOS 15 或 watchOS 8.0。
用 Swift 5.5 写的项目可以依赖用 Swift 4.2 或 Swift 4 写的项目反之亦然。这意味着如果你将一个大的项目分解成多个框架framework你可以逐个地将框架从 Swift 4 代码迁移到 Swift 5.5。

View File

@ -14,11 +14,11 @@ print("Hello, world!")
>
> 最好的体验是把这一章作为 Playground 文件在 Xcode 中打开。 Playgrounds 允许你可以编辑代码并立刻看到输出结果。
>
> [Download Playground](https://docs.swift.org/swift-book/GuidedTour/GuidedTour.playground.zip)
> [下载 Playground](https://docs.swift.org/swift-book/GuidedTour/GuidedTour.playground.zip)
## 简单值 {#simple-values}
使用 `let` 来声明常量,使用 `var` 来声明变量。一个常量的值,在编译的时候,并不需要有明确的值,但是你只能为它赋值一次。这说明你可以用一个常量来命名一个值,一次赋值就可在多个地方使用。
使用 `let` 来声明常量,使用 `var` 来声明变量。一个常量的值,在编译的时候,并不需要有明确的值,但是你只能为它赋值一次。这说明你可以用一个常量来命名一个值,一次赋值就可在多个地方使用。
```swift
var myVariable = 42
@ -65,7 +65,7 @@ let fruitSummary = "I have \(apples + oranges) pieces of fruit."
>
> 使用 `\()` 来把一个浮点计算转换成字符串,并加上某人的名字,和他打个招呼。
使用三个双引号(`"""`)来包含多行字符串内容,字符串中的内容(包括引号、空格、换行符等)都会保留下来。举个例子:
使用三个双引号(`"""`)来包含多行字符串内容。每行行首的缩进会被去除,直到和结尾引号的缩进相匹配。举个例子:
```swift
let quotation = """
@ -87,14 +87,21 @@ var occupations = [
occupations["Jayne"] = "Public Relations"
```
数组在添加元素时会自动变大。
```swift
shoppingList.append("blue paint")
print(shoppingList)
```
使用初始化语法来创建一个空数组或者空字典。
```swift
let emptyArray = [String]()
let emptyDictionary = [String: Float]()
let emptyArray: [String] = []
let emptyDictionary: [String: Float] = [:]
```
如果类型信息可以被推断出来,你可以用 `[]``[:]` 来创建空数组和空字典——就像你声明变量或者给函数传参数的时候一样
如果类型信息可以被推断出来,你可以用 `[]``[:]` 来创建空数组和空字典——比如,在给变量赋新值或者给函数传参数的时候。
```swift
shoppingList = []
@ -138,6 +145,7 @@ if let name = optionalName {
> 把 `optionalName` 改成 `nil`greeting 会是什么?添加一个 `else` 语句,当 `optionalName``nil` 时给 greeting 赋一个不同的值。
如果变量的可选值是 `nil`,条件会判断为 `false`,大括号中的代码会被跳过。如果不是 `nil`,会将值解包并赋给 `let` 后面的常量,这样代码块中就可以使用这个值了。
另一种处理可选值的方法是通过使用 `??` 操作符来提供一个默认值。如果可选值缺失的话,可以使用默认值来代替。
```swift
@ -179,7 +187,7 @@ let interestingNumbers = [
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
for (_, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
@ -187,11 +195,12 @@ for (kind, numbers) in interestingNumbers {
}
}
print(largest)
// 输出 "25"
```
> 练习
>
> 添加另一个变量来记录最大数字的种类kind同时仍然记录这个最大数字的值
> 将 _ 替换成变量名,以确定哪种类型的值是最大的
使用 `while` 来重复运行一段代码直到条件改变。循环条件也可以在结尾,保证能至少循环一次。
@ -234,7 +243,7 @@ greet(person:"Bob", day: "Tuesday")
> 练习
>
> 删除 `day` 参数,添加一个参数来表示今天吃了什么午饭
> 删除 `day` 参数,在这个欢迎语中添加一个参数来表示今天的特价菜
默认情况下,函数使用它们的参数名称作为它们参数的标签,在参数名称前可以自定义参数标签,或者使用 `_` 表示不使用参数标签。
@ -314,7 +323,7 @@ var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)
```
函数实际上是一种特殊的闭包:它是一段能之后被调取的代码。闭包中的代码能访问闭包作用域中的变量和函数,即使闭包是在一个不同的作用域被执行的 - 你已经在嵌套函数的例子中看过了。你可以使用 `{}` 来创建一个匿名闭包。使用 `in` 将参数和返回值类型的声明与闭包函数体进行分离。
函数实际上是一种特殊的闭包:它是一段能之后被调取的代码。闭包中的代码能访问闭包作用域中的变量和函数,即使闭包是在一个不同的作用域被执行的——你已经在嵌套函数的例子中看过了。你可以使用 `{}` 来创建一个匿名闭包。使用 `in` 将参数和返回值类型的声明与闭包函数体进行分离。
```swift
numbers.map({
@ -335,7 +344,7 @@ let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)
```
你可以通过参数位置而不是参数名字来引用参数——这个方法在非常短的闭包中非常有用。当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。当一个闭包是传给函数的唯一参数,你可以完全忽略括号。
你可以通过参数位置而不是参数名字来引用参数——这个方法在非常短的闭包中非常有用。当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。当一个闭包是传给函数的唯一参数,你可以完全忽略括号。
```swift
let sortedNumbers = numbers.sorted { $0 > $1 }
@ -419,7 +428,7 @@ test.simpleDescription()
>
> 创建 `NamedShape` 的另一个子类 `Circle`,构造器接收两个参数,一个是半径一个是名称,在子类 `Circle` 中实现 `area()``simpleDescription()` 方法。
除了储存简单的属性之外,属性可以有 getter 和 setter 。
除了简单的存储属性,还有使用 getter 和 setter 的计算属性
```swift
class EquilateralTriangle: NamedShape {
@ -450,7 +459,7 @@ triangle.perimeter = 9.9
print(triangle.sideLength)
```
`perimeter` 的 setter 中,新值的名字是 `newValue`。你可以在 `set` 之后显式设置一个名字。
`perimeter` 的 setter 中,新值的名字是 `newValue`。你可以在 `set` 之后的圆括号中显式设置一个名字。
注意 `EquilateralTriangle` 类的构造器执行了三步:
@ -484,7 +493,7 @@ triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)
```
处理变量的可选值时,你可以在操作(比如方法、属性和子脚本)之前加 `?`。如果 `?` 之前的值是 `nil``?` 后面的东西都会被忽略,并且整个表达式返回 `nil`。否则,`?` 之后的东西都会被运行。在这两种情况下,整个表达式的值也是一个可选值。
处理变量的可选值时,你可以在操作(比如方法、属性和子脚本)之前加 `?`。如果 `?` 之前的值是 `nil``?` 后面的东西都会被忽略,并且整个表达式返回 `nil`。否则,可选值会被解包,之后的所有代码都会按照解包后的值运行。在这两种情况下,整个表达式的值也是一个可选值。
```swift
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
@ -525,7 +534,7 @@ let aceRawValue = ace.rawValue
默认情况下Swift 按照从 0 开始每次加 1 的方式为原始值进行赋值,不过你可以通过显式赋值进行改变。在上面的例子中,`Ace` 被显式赋值为 1并且剩下的原始值会按照顺序赋值。你也可以使用字符串或者浮点数作为枚举的原始值。使用 `rawValue` 属性来访问一个枚举成员的原始值。
使用 `init?(rawValue:)` 初始化构造器来创建一个带有原始值的枚举成员。如果存在与原始值相应的枚举成员就返回该枚举成员,否则就返回 `nil`
使用 `init?(rawValue:)` 初始化构造器来从原始值创建一个枚举实例。如果存在与原始值相应的枚举成员就返回该枚举成员,否则就返回 `nil`
```swift
if let convertedRank = Rank(rawValue: 3) {
@ -559,9 +568,9 @@ let heartsDescription = hearts.simpleDescription()
>
> 给 `Suit` 添加一个 `color()` 方法,对 `spades``clubs` 返回 “black” ,对 `hearts``diamonds` 返回 “red” 。
注意在上面的例子中用了两种方式引用 `hearts` 枚举成员:给 `hearts` 常量赋值时,枚举成员 `Suit.hearts` 需要用全名来引用,因为常量没有显式指定类型。在 `switch` 里,枚举成员使用缩写 `.hearts` 来引用,因为 `self` 的值已经是一个 `suit` 类型,在已知变量类型的情况下可以使用缩写。
注意在上面的例子中用了两种方式引用 `hearts` 枚举成员:给 `hearts` 常量赋值时,枚举成员 `Suit.hearts` 需要用全名来引用,因为常量没有显式指定类型。在 `switch` 里,枚举成员使用缩写 `.hearts` 来引用,因为 `self` 的值已经是一个 `suit` 类型。在任何已知变量类型的情况下可以使用缩写。
如果枚举成员的实例有原始值,那么这些值是在声明的时候就已经决定了,这意味着不同枚举实例的枚举成员总会有一个相同的原始值。当然我们也可以为枚举成员设定关联值,关联值是在创建实例时决定的。这意味着不同的枚举成员的关联值可以不同。你可以把关联值想象成枚举成员的寄存属性。例如,考虑从服务器获取日出和日落的时间的情况。服务器会返回正常结果或者错误信息。
如果枚举成员的实例有原始值,那么这些值是在声明的时候就已经决定了,这意味着不同枚举实例的枚举成员总会有一个相同的原始值。当然我们也可以为枚举成员设定关联值,关联值是在创建实例时决定的。这意味着同一枚举成员不同实例的关联值可以不同。你可以把关联值想象成枚举成员实例的存储属性。例如,考虑从服务器获取日出和日落的时间的情况。服务器会返回正常结果或者错误信息。
```swift
enum ServerResponse {
@ -584,7 +593,7 @@ case let .failure(message):
>
> 给 `ServerResponse` 和 switch 添加第三种情况。
注意日升和日落时间是如何从 `ServerResponse` 中提取到并`switch` `case` 相匹配的。
注意 `ServerResponse` 的值在`switch`分支匹配时,日升和日落时间是如何从该值中提取出来的。
使用 `struct` 来创建一个结构体。结构体和类有很多相同的地方,包括方法和构造器。它们之间最大的一个区别就是结构体是传值,类是传引用。
@ -602,7 +611,7 @@ let threeOfSpadesDescription = threeOfSpades.simpleDescription()
> 练习
>
> `Card` 添加一个方法,创建一副完整的扑克牌并把每张牌的 rank 和 suit 对应起来
> 一个方法,创建一副完整的扑克牌,这些牌是所有 rank 和 suit 的组合
## 协议和扩展 {#protocols-and-extensions}
@ -642,7 +651,7 @@ let bDescription = b.simpleDescription
> 练习
>
> 写一个实现这个协议的枚举。
> `ExampleProtocol` 再增加一个要求。你需要怎么改 `SimpleClass``SimpleStructure` 才能保证它们仍旧遵循这个协议?
注意声明 `SimpleStructure` 时候 `mutating` 关键字用来标记一个会修改结构体的方法。`SimpleClass` 的声明不需要标记任何方法,因为类中的方法通常可以修改类属性(类的性质)。
@ -763,7 +772,7 @@ print(fridgeIsOpen)
```swift
func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
var result = [Item]()
var result: [Item] = []
for _ in 0..<numberOfTimes {
result.append(item)
}
@ -788,15 +797,16 @@ possibleInteger = .some(100)
```swift
func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
where T.Element: Equatable, T.Element == U.Element
{
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
return false
}
return false
}
anyCommonElements([1, 2, 3], [3])
```

View File

@ -75,7 +75,7 @@ var red, green, blue: Double
### 常量和变量的命名 {#naming}
常量和变量名可以包含任何字符,包括 Unicode 字符:
常量和变量名可以包含几乎所有的字符,包括 Unicode 字符:
```swift
let π = 3.14159
@ -116,7 +116,7 @@ print(friendlyWelcome)
// 输出“Bonjour!”
```
`print(_:separator:terminator:)` 是一个用来输出一个或多个值到适当输出区的全局函数。如果你用 Xcode`print(_:separator:terminator:)` 将会输出内容到“console”面板上。`separator``terminator` 参数具有默认值,因此你调用这个函数的时候可以忽略它们。默认情况下,该函数通过添加换行符来结束当前行。如果不想换行,可以传递一个空字符串给 `terminator` 参数--例如,`print(someValue, terminator:"")` 。关于参数默认值的更多信息,请参考 [默认参数值](./06_Functions.md#default_parameter_values)。
`print(_:separator:terminator:)` 是一个用来输出一个或多个值到适当输出区的全局函数。如果你用 Xcode`print(_:separator:terminator:)` 将会输出内容到“console”面板上。`separator``terminator` 参数具有默认值,因此你调用这个函数的时候可以忽略它们。默认情况下,该函数通过添加换行符来结束当前行。如果不想换行,可以传递一个空字符串给 `terminator` 参数--例如,`print(someValue, terminator:"")` 。关于参数默认值的更多信息,请参考 [默认参数值](./06_Functions.md#default-parameter-values)。
Swift 用*字符串插值string interpolation*的方式把常量名或者变量名当做占位符加入到长字符串中Swift 会用当前常量或变量的值替换这些占位符。将常量或变量名放入圆括号中,并在开括号前使用反斜杠将其转义:
@ -127,7 +127,7 @@ print("The current value of friendlyWelcome is \(friendlyWelcome)")
> 注意
>
> 字符串插值所有可用的选项,请参考 [字符串插值](./03_Strings_and_Characters.md#string_interpolation)。
> 字符串插值所有可用的选项,请参考 [字符串插值](./03_Strings_and_Characters.md#string-interpolation)。
## 注释 {#comments}
@ -200,7 +200,7 @@ Swift 也提供了一个特殊的无符号类型 `UInt`,长度与当前平台
> 注意
>
> 尽量不要使用 `UInt`,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用 `Int`,即使你要存储的值已知是非负的。统一使用 `Int` 可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推断,请参考 [类型安全和类型推断](#type_safety_and_type_inference)。
> 尽量不要使用 `UInt`,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用 `Int`,即使你要存储的值已知是非负的。统一使用 `Int` 可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推断,请参考 [类型安全和类型推断](#type-safety-and-type-inference)。
## 浮点数 {#floating-point-numbers}
@ -213,7 +213,7 @@ Swift 也提供了一个特殊的无符号类型 `UInt`,长度与当前平台
> 注意
>
> `Double` 精确度很高至少有15位数字,而 `Float` 只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围,在两种类型都匹配的情况下,将优先选择 `Double`
> `Double` 精确度很高,至少有 15 位小数,而 `Float` 只有 6 位小数。选择哪个类型取决于你的代码需要处理的值的范围,在两种类型都匹配的情况下,将优先选择 `Double`
## 类型安全和类型推断 {#type-safety-and-type-inference}
@ -477,11 +477,11 @@ print("The status message is \(http200Status.description)")
// 输出“The status message is OK”
```
作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个 `(Int, String)` 元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考 [函数参数与返回值](./06_Functions.md#Function_Parameters_and_Return_Values)。
作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个 `(Int, String)` 元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考 [函数参数与返回值](./06_Functions.md#Function-Parameters-and-Return-Values)。
> 注意
>
> 当遇到一些相关值的简单分组时,元组是很有用的。元组不适合用来创建复杂的数据结构。如果你的数据结构比较复杂,不要使用元组,用类或结构体去建模。欲获得更多信息,请参考 [结构体和类](./09_Classes_and_Structures.md)。
> 当遇到一些相关值的简单分组时,元组是很有用的。元组不适合用来创建复杂的数据结构。如果你的数据结构比较复杂,不要使用元组,用类或结构体去建模。欲获得更多信息,请参考 [结构体和类](./09_Structures_And_Classes.md)。
## 可选类型 {#optionals}
@ -589,7 +589,7 @@ if let actualNumber = Int(possibleNumber) {
你可以在可选绑定中使用常量和变量。如果你想在 `if` 语句的第一个分支中操作 `actualNumber` 的值,你可以改成 `if var actualNumber`,这样可选类型包含的值就会被赋给一个变量而非常量。
你可以包含多个可选绑定或多个布尔条件在一个 `if` 语句中,只要使用逗号分开就行。只要有任意一个可选绑定的值为 `nil`,或者任意一个布尔条件为 `false`,则整个 `if` 条件判断为 `false`,这时你就需要使用嵌套 `if` 条件语句来处理,如下所示
你可以包含多个可选绑定或多个布尔条件在一个 `if` 语句中,只要使用逗号分开就行。只要有任意一个可选绑定的值为 `nil`,或者任意一个布尔条件为 `false`,则整个 `if` 条件判断为 `false`。下面的两个 `if` 语句是等价的
```swift
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
@ -609,7 +609,7 @@ if let firstNumber = Int("4") {
> 注意
>
> 在 `if` 条件语句中使用常量和变量来创建一个可选绑定,仅在 `if` 语句的句中(`body`)中才能获取到值。相反,在 `guard` 语句中使用常量和变量来创建一个可选绑定,仅在 `guard` 语句外且在语句后才能获取到值,请参考 [提前退出](./05_Control_Flow.md#early_exit)。
> 在 `if` 条件语句中使用常量和变量来创建一个可选绑定,仅在 `if` 语句的句中(`body`)中才能获取到值。相反,在 `guard` 语句中使用常量和变量来创建一个可选绑定,仅在 `guard` 语句外且在语句后才能获取到值,请参考 [提前退出](./05_Control_Flow.md#early-exit)。
### 隐式解析可选类型 {#implicityly-unwrapped-optionals}
@ -617,9 +617,9 @@ if let firstNumber = Int("4") {
有时候在程序架构中第一次被赋值之后可以确定一个可选类型_总会_有值。在这种情况下每次都要判断和解析可选值是非常低效的因为可以确定它总会有值。
这种类型的可选状态被定义为隐式解析可选类型implicitly unwrapped optionals。把想要用作可选的类型的后面的问号`String?`)改成感叹号(`String!`)来声明一个隐式解析可选类型。
这种类型的可选状态被定义为隐式解析可选类型implicitly unwrapped optionals。把想要用作可选的类型的后面的问号`String?`)改成感叹号(`String!`)来声明一个隐式解析可选类型。与其在使用时把感叹号放在可选类型的名称的后面,你可以在定义它时,直接把感叹号放在可选类型的后面。
当可选类型被第一次赋值之后就可以确定之后一直有值的时候,隐式解析可选类型非常有用。隐式解析可选类型主要被用在 Swift 中类的构造过程中,请参考 [无主引用以及隐式解析可选属性](./23_Automatic_Reference_Counting.md#unowned_references_and_implicitly_unwrapped_optional_properties)。
当可选类型被第一次赋值之后就可以确定之后一直有值的时候,隐式解析可选类型非常有用。隐式解析可选类型主要被用在 Swift 中类的构造过程中,请参考 [无主引用以及隐式解析可选属性](./24_Automatic_Reference_Counting.md#unowned-references-and-implicitly-unwrapped-optional-properties)。
一个隐式解析可选类型其实就是一个普通的可选类型,但是可以被当做非可选类型来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选类型 `String` 和隐式解析可选类型 `String` 之间的区别:
@ -631,13 +631,15 @@ let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感叹号
```
你可以把隐式解析可选类型当做一个可以自动解析的可选类型。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾
你可以把隐式解析可选类型当做一个可以自动解析的可选类型。当你使用一个隐式解析可选值时Swift 首先会把它当作普通的可选值如果它不能被当成可选类型使用Swift 会强制解析可选值。在以上的代码中,可选值 `assumedString` 在把自己的值赋给 `implicitString` 之前会被强制解析,原因是 `implicitString` 本身的类型是非可选类型的 `String`。在下面的代码中,`optionalString` 并没有显式的数据类型。那么根据类型推断,它就是一个普通的可选类型
```swift
let optionalString = assumedString
// optionalString 的类型是 "String?"assumedString 也没有被强制解析。
```
> 注意
>
> 如果你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一个惊叹号一样。
如果你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一个感叹号一样。
仍然可以把隐式解析可选类型当做普通可选类型来判断它是否包含值:
你可以把隐式解析可选类型当做普通可选类型来判断它是否包含值:
```swift
if assumedString != nil {

View File

@ -2,11 +2,11 @@
*运算符*是检查、改变、合并值的特殊符号或短语。例如,加号(`+`)将两个数相加(如 `let i = 1 + 2`)。更复杂的运算例子包括逻辑与运算符 `&&`(如 `if enteredDoorCode && passedRetinaScan`)。
Swift 支持大部分标准 C 语言的运算符,且为了减少常见编码错误做了部分改进。如:赋值符(`=`)不再有返回值,这样就消除了手误将判等运算符(`==`)写成赋值符导致代码错误的缺陷。算术运算符(`+``-``*``/``%` 等)的结果会被检测并禁止值溢出,以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然允许你使用 Swift 的溢出运算符来实现溢出。详情参见 [溢出运算符](./26_Advanced_Operators.md#overflow_operators)。
Swift 支持运算符你可能在别的语言比如 C 语言里已经认识了,同时为了减少常见编码错误对它们做了部分改进。如:赋值符(`=`)不再有返回值,这样就消除了手误将判等运算符(`==`)写成赋值符导致代码错误的缺陷。算术运算符(`+``-``*``/``%` 等)的结果会被检测并禁止值溢出,以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然允许你使用 Swift 的溢出运算符来实现溢出。详情参见 [溢出运算符](./27_Advanced_Operators.md#overflow-operators)。
Swift 还提供了 C 语言没有的区间运算符,例如 `a..<b``a...b`,这方便我们表达一个区间内的数值。
本章节只描述了 Swift 中的基本运算符,[高级运算符](./26_Advanced_Operators.md) 这章会包含 Swift 中的高级运算符,及如何自定义运算符,及如何进行自定义类型的运算符重载。
本章节只描述了 Swift 中的基本运算符,[高级运算符](./27_Advanced_Operators.md) 这章会包含 Swift 中的高级运算符,及如何自定义运算符,及如何进行自定义类型的运算符重载。
## 术语 {#terminology}
@ -62,7 +62,7 @@ Swift 中所有数值类型都支持了基本的四则*算术运算符*
10.0 / 2.5 // 等于 4.0
```
与 C 语言和 Objective-C 不同的是Swift 默认情况下不允许在数值运算中出现溢出情况。但是你可以使用 Swift 的溢出运算符来实现溢出运算(如 `a &+ b`)。详情参见 [溢出运算符](./26_Advanced_Operators.md#overflow_operators)。
与 C 语言和 Objective-C 不同的是Swift 默认情况下不允许在数值运算中出现溢出情况。但是你可以使用 Swift 的溢出运算符来实现溢出运算(如 `a &+ b`)。详情参见 [溢出运算符](./27_Advanced_Operators.md#overflow-operators)。
加法运算符也可用于 `String` 的拼接:
@ -157,7 +157,7 @@ a += 2
## 比较运算符Comparison Operators {#comparison-operators}
所有标准 C 语言中的*比较运算符*都可以在 Swift 中使用
Swift 支持以下的比较运算符
- 等于(`a == b`
- 不等于(`a != b`
@ -168,7 +168,7 @@ a += 2
> 注意
>
> Swift 也提供恒等(`===`)和不恒等(`!==`)这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在 [类与结构](./09_Classes_and_Structures.md) 章节的 **Identity Operators** 部分。
> Swift 也提供恒等(`===`)和不恒等(`!==`)这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在 [类与结构](./09_Structures_And_Classes.md) 章节的 **Identity Operators** 部分。
每个比较运算都返回了一个标识表达式是否成立的布尔值:
@ -267,7 +267,7 @@ if hasHeader {
a != nil ? a! : b
```
上述代码使用了三元运算符。当可选类型 `a` 的值不为空时,进行强制解`a!`),访问 `a` 中的值;反之返回默认值 `b`。无疑空合运算符(`??`)提供了一种更为优雅的方式去封装条件判断和解两种行为,显得简洁以及更具可读性。
上述代码使用了三元运算符。当可选类型 `a` 的值不为空时,进行强制解`a!`),访问 `a` 中的值;反之返回默认值 `b`。无疑空合运算符(`??`)提供了一种更为优雅的方式去封装条件判断和解两种行为,显得简洁以及更具可读性。
> 注意
>
@ -286,7 +286,7 @@ var colorNameToUse = userDefinedColorName ?? defaultColorName
`userDefinedColorName` 变量被定义为一个可选的 `String` 类型,默认值为 `nil`。由于 `userDefinedColorName` 是一个可选类型,我们可以使用空合运算符去判断其值。在上一个例子中,通过空合运算符为一个名为 `colorNameToUse` 的变量赋予一个字符串类型初始值。
由于 `userDefinedColorName` 值为空,因此表达式 `userDefinedColorName ?? defaultColorName` 返回 `defaultColorName` 的值,即 `red`
如果你分配一个非空值(`non-nil`)给 `userDefinedColorName`,再次执行空合运算,运算结果为封包在 `userDefaultColorName` 中的值,而非默认值。
如果你分配一个非空值(`non-nil`)给 `userDefinedColorName`,再次执行空合运算,运算结果为封包在 `userDefinedColorName` 中的值,而非默认值。
```swift
userDefinedColorName = "green"
@ -402,7 +402,7 @@ if !allowedEntry {
在示例代码中,小心地选择布尔常量或变量有助于代码的可读性,并且避免使用双重逻辑非运算,或混乱的逻辑语句。
### 逻辑与运算符 #{logical_and_operator}
### 逻辑与运算符 {#logical-and-operator}
*逻辑与运算符*`a && b`)表达了只有 `a``b` 的值都为 `true` 时,整个表达式的值才会是 `true`
@ -421,7 +421,7 @@ if enteredDoorCode && passedRetinaScan {
// 输出“ACCESS DENIED”
```
### 逻辑或运算符 #{logical_or_operator}
### 逻辑或运算符 {#logical-or-operator}
逻辑或运算符(`a || b`)是一个由两个连续的 `|` 组成的中置运算符。它表示了两个逻辑表达式的其中一个为 `true`,整个表达式就为 `true`

View File

@ -1,8 +1,8 @@
# 字符串和字符
*字符串*是一系列字符的集合,例如 `"hello, world"``"albatross"`。Swift 的字符串通过 `String` 类型来表示。而 `String` 内容的访问方式有多种,例如以 `Character` 值的集合。
*字符串*是一系列字符的集合,例如 `"hello, world"``"albatross"`。Swift 的字符串通过 `String` 类型来表示。而 `String` 内容的访问方式有多种,例如以 `Character` 值的集合。
Swift 的 `String``Character` 类型提供了一种快速且兼容 Unicode 的方式来处理代码中的文本内容。创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。通过 `+` 符号就可以非常简单的实现两个字符串的拼接操作。与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。你可以在已有字符串中插入常量、变量、字面量和表达式从而形成更长的字符串,这一过程也被为字符串插值。尤其是在为显示、存储和打印创建自定义字符串值时,字符串插值操作尤其有用。
Swift 的 `String``Character` 类型提供了一种快速且兼容 Unicode 的方式来处理代码中的文本内容。创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。通过 `+` 符号就可以非常简单的实现两个字符串的拼接操作。与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。你可以在已有字符串中插入常量、变量、字面量和表达式从而形成更长的字符串,这一过程也被为字符串插值。尤其是在为显示、存储和打印创建自定义字符串值时,字符串插值操作尤其有用。
尽管语法简易,但 Swift 中的 `String` 类型的实现却很快速和现代化。每一个字符串都是由编码无关的 Unicode 字符组成,并支持访问字符的多种 Unicode 表示形式。
@ -106,9 +106,9 @@ Escaping all three quotes \"\"\"
### 扩展字符串分隔符 {#extended-string-delimiters}
您可以将字符串文字放在扩展分隔符中,这样字符串中的特殊字符将会被直接包含而非转义后的效果。将字符串放在引号(`"`)中并用数字符号(``)括起来。例如,打印字符串文字 `"Line 1 \nLine 2"` 会打印换行符转义序列(`\n`)而不是给文字换行。
您可以将字符串文字放在扩展分隔符中,这样字符串中的特殊字符将会被直接包含而非转义后的效果。将字符串放在引号(`"`)中并用数字符号(`#`)括起来。例如,打印字符串文字 `#"Line 1 \nLine 2"#` 会打印换行符转义序列(`\n`)而不是给文字换行。
如果需要字符串文字中字符的特殊效果,请匹配转义字符(`\`)后面添加与起始位置个数相匹配的 `#` 符。 例如,如果您的字符串是 `"Line 1 \nLine 2"` 并且您想要换行,则可以使用 `#“Line 1 \#nLine 2”#` 来代替。 同样,`###"Line1 \###nLine2"###` 也可以实现换行效果。
如果需要字符串文字中字符的特殊效果,请匹配转义字符(`\`)后面添加与起始位置个数相匹配的 `#` 符。 例如,如果您的字符串是 `#"Line 1 \nLine 2"#` 并且您想要换行,则可以使用 `#"Line 1 \#nLine 2"#` 来代替。 同样,`###"Line1 \###nLine2"###` 也可以实现换行效果。
扩展分隔符创建的字符串文字也可以是多行字符串文字。 您可以使用扩展分隔符在多行字符串中包含文本 `"""`,覆盖原有的结束文字的默认行为。例如:
@ -157,7 +157,7 @@ constantString += " and another Highlander"
## 字符串是值类型 {#strings-are-value-types}
在 Swift 中 `String` 类型是*值类型*。如果你创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。在前述任一情况下,都会对已有字符串值创建新副本,并对该新副本而非原始字符串进行传递或赋值操作。值类型在 [结构体和枚举是值类型](./09_Classes_and_Structures.md#structures_and_enumerations_are_value_types) 中进行了详细描述。
在 Swift 中 `String` 类型是*值类型*。如果你创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。在前述任一情况下,都会对已有字符串值创建新副本,并对该新副本而非原始字符串进行传递或赋值操作。值类型在 [结构体和枚举是值类型](./09_Structures_And_Classes.md#structures-and-enumerations-are-value-types) 中进行了详细描述。
Swift 默认拷贝字符串的行为保证了在函数/方法向你传递的字符串所属权属于你,无论该值来自于哪里。你可以确信传递的字符串不会被修改,除非你自己去修改它。
@ -178,7 +178,7 @@ for character in "Dog!🐶" {
// 🐶
```
`for-in` 循环在 [For 循环](./05_Control_Flow.md#for_loops) 中进行了详细描述。
`for-in` 循环在 [For 循环](./05_Control_Flow.md#for-loops) 中进行了详细描述。
另外,通过标明一个 `Character` 类型并用字符字面量进行赋值,可以建立一个独立的字符常量或变量:
@ -269,6 +269,20 @@ let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
`multiplier` 的值也作为字符串中后面表达式的一部分。该表达式计算 `Double(multiplier) * 2.5` 的值并将结果(`7.5`)插入到字符串中。在这个例子中,表达式写为 `\(Double(multiplier) * 2.5)` 并包含在字符串字面量中。
你可以使用扩展字符串分隔符创建字符串,来包含不想作为字符串插值处理的字符。例如:
```swift
print(#"Write an interpolated string in Swift using \(multiplier)."#)
// 打印 "Write an interpolated string in Swift using \(multiplier)."
```
如果要在使用扩展字符串分隔符的字符串中使用字符串插值,需要在反斜杠后面添加与开头和结尾数量相同扩展字符串分隔符。例如:
```swift
print(#"6 times 7 is \#(6 * 7)."#)
// 打印 "6 times 7 is 42."
```
> 注意
>
> 插值字符串中写在括号中的表达式不能包含非转义反斜杠(`\`),并且不能包含回车或换行符。不过,插值字符串可以包含其他字面量。
@ -384,7 +398,7 @@ greeting[index]
```swift
greeting[greeting.endIndex] // error
greeting.index(after: endIndex) // error
greeting.index(after: greeting.endIndex) // error
```
使用 `indices` 属性会创建一个包含全部索引的范围(`Range`),用来在一个字符串中访问单个字符。
@ -430,7 +444,7 @@ welcome.removeSubrange(range)
## 子字符串 {#substrings}
当你从字符串中获取一个子字符串 —— 例如,使用下标或者 `prefix(_:)` 之类的方法 —— 就可以得到一个 `SubString` 的实例,而非另外一个 `String`。Swift 里的 `SubString` 绝大部分函数都跟 `String` 一样,意味着你可以使用同样的方式去操作 `SubString``String`。然而,跟 `String` 不同的是,你只有在短时间内需要操作字符串时,才会使用 `SubString`。当你需要长时间保存结果时,就把 `SubString` 转化为 `String` 的实例:
当你从字符串中获取一个子字符串 —— 例如,使用下标或者 `prefix(_:)` 之类的方法 —— 就可以得到一个 `Substring` 的实例,而非另外一个 `String`。Swift 里的 `Substring` 绝大部分函数都跟 `String` 一样,意味着你可以使用同样的方式去操作 `Substring``String`。然而,跟 `String` 不同的是,你只有在短时间内需要操作字符串时,才会使用 `Substring`。当你需要长时间保存结果时,就把 `Substring` 转化为 `String` 的实例:
```swift
let greeting = "Hello, world!"
@ -442,15 +456,15 @@ let beginning = greeting[..<index]
let newString = String(beginning)
```
就像 `String`,每一个 `SubString` 都会在内存里保存字符集。而 `String``SubString` 的区别在于性能优化上,`SubString` 可以重用原 `String` 的内存空间,或者另一个 `SubString` 的内存空间(`String` 也有同样的优化,但如果两个 `String` 共享内存的话,它们就会相等)。这一优化意味着你在修改 `String``SubString` 之前都不需要消耗性能去复制内存。就像前面说的那样,`SubString` 不适合长期存储 —— 因为它重用了原 `String` 的内存空间,原 `String` 的内存空间必须保留直到它的 `SubString` 不再被使用为止。
就像 `String`,每一个 `Substring` 都会在内存里保存字符集。而 `String``Substring` 的区别在于性能优化上,`Substring` 可以重用原 `String` 的内存空间,或者另一个 `Substring` 的内存空间(`String` 也有同样的优化,但如果两个 `String` 共享内存的话,它们就会相等)。这一优化意味着你在修改 `String``Substring` 之前都不需要消耗性能去复制内存。就像前面说的那样,`Substring` 不适合长期存储 —— 因为它重用了原 `String` 的内存空间,原 `String` 的内存空间必须保留直到它的 `Substring` 不再被使用为止。
上面的例子,`greeting` 是一个 `String`,意味着它在内存里有一片空间保存字符集。而由于 `beginning``greeting``SubString`,它重用了 `greeting` 的内存空间。相反,`newString` 是一个 `String` —— 它是使用 `SubString` 创建的,拥有一片自己的内存空间。下面的图展示了他们之间的关系:
上面的例子,`greeting` 是一个 `String`,意味着它在内存里有一片空间保存字符集。而由于 `beginning``greeting``Substring`,它重用了 `greeting` 的内存空间。相反,`newString` 是一个 `String` —— 它是使用 `Substring` 创建的,拥有一片自己的内存空间。下面的图展示了他们之间的关系:
![](https://docs.swift.org/swift-book/_images/stringSubstring_2x.png)
> 注意
>
> `String``SubString` 都遵循 `StringProtocol<//apple_ref/swift/intf/s:s14StringProtocolP>` 协议,这意味着操作字符串的函数使用 `StringProtocol` 会更加方便。你可以传入 `String``SubString` 去调用函数。
> `String``Substring` 都遵循 [`StringProtocol`](https://developer.apple.com/documentation/swift/stringprotocol) 协议,这意味着操作字符串的函数使用 `StringProtocol` 会更加方便。你可以传入 `String``Substring` 去调用函数。
## 比较字符串 {#comparing-strings}
@ -458,7 +472,7 @@ Swift 提供了三种方式来比较文本值:字符串字符相等、前缀
### 字符串/字符相等 {#string-and-character-equality}
字符串/字符可以用等于操作符(`==`)和不等于操作符(`!=`),详细描述在 [比较运算符](./02_Basic_Operators.md#comparison_operators)
字符串/字符可以用等于操作符(`==`)和不等于操作符(`!=`),详细描述在 [比较运算符](./02_Basic_Operators.md#comparison-operators)
```swift
let quotation = "We're a lot alike, you and I."
@ -556,13 +570,13 @@ print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
> 注意
>
> `hasPrefix(_:)``hasSuffix(_:)` 方法都是在每个字符串中逐字符比较其可扩展的字符群集是否标准相等,详细描述在 [字符串/字符相等](#string_and_character_equality)。
> `hasPrefix(_:)``hasSuffix(_:)` 方法都是在每个字符串中逐字符比较其可扩展的字符群集是否标准相等,详细描述在 [字符串/字符相等](#string-and-character-equality)。
## 字符串的 Unicode 表示形式 {#unicode-representations-of-strings}
当一个 Unicode 字符串被写进文本文件或者其他储存时,字符串中的 Unicode 标量会用 Unicode 定义的几种 `编码格式`encoding forms编码。每一个字符串中的小块编码都被称 `代码单元`code units。这些包括 UTF-8 编码格式(编码字符串为 8 位的代码单元), UTF-16 编码格式(编码字符串位 16 位的代码单元),以及 UTF-32 编码格式编码字符串32位的代码单元
Swift 提供了几种不同的方式来访问字符串的 Unicode 表示形式。你可以利用 `for-in` 来对字符串进行遍历,从而以 Unicode 可扩展的字符群集的方式访问每一个 `Character` 值。该过程在 [使用字符](#working_with_characters) 中进行了描述。
Swift 提供了几种不同的方式来访问字符串的 Unicode 表示形式。你可以利用 `for-in` 来对字符串进行遍历,从而以 Unicode 可扩展的字符群集的方式访问每一个 `Character` 值。该过程在 [使用字符](#working-with-characters) 中进行了描述。
另外,能够以其他三种 Unicode 兼容的方式访问字符串的值:

View File

@ -37,7 +37,7 @@ Swift 中数组的完整写法为 `Array<Element>`,其中 `Element` 是这个
你可以使用构造语法来创建一个由特定数据类型构成的空数组:
```swift
var someInts = [Int]()
var someInts: [Int] = []
print("someInts is of type [Int] with \(someInts.count) items.")
// 打印“someInts is of type [Int] with 0 items.”
```
@ -235,7 +235,7 @@ for (index, value) in shoppingList.enumerated() {
// Item 5: Bananas
```
更多关于 `for-in` 循环的介绍请参见 [For 循环](05_Control_Flow.html#for_loops)。
更多关于 `for-in` 循环的介绍请参见 [For 循环](./05_Control_Flow.md#for-loops)。
## 集合Sets {#sets}
@ -380,7 +380,7 @@ for genre in favoriteGenres {
// Hip hop
```
更多关于 `for-in` 循环的信息,参见 [For 循环](./05_Control_Flow.md#for_loops)。
更多关于 `for-in` 循环的信息,参见 [For 循环](./05_Control_Flow.md#for-loops)。
Swift 的 `Set` 类型没有确定的顺序,为了按照特定顺序来遍历一个集合中的值可以使用 `sorted()` 方法,它将返回一个有序数组,这个数组的元素排列顺序由操作符 `<` 对元素进行比较的结果来确定。
@ -473,7 +473,7 @@ Swift 的字典使用 `Dictionary<Key, Value>` 定义,其中 `Key` 是一种
你可以像数组一样使用构造语法创建一个拥有确定类型的空字典:
```swift
var namesOfIntegers = [Int: String]()
var namesOfIntegers: [Int: String] = [:]
// namesOfIntegers 是一个空的 [Int: String] 字典
```
@ -613,7 +613,7 @@ for (airportCode, airportName) in airports {
// LHR: London Heathrow
```
更多关于 `for-in` 循环的信息,参见 [For 循环](./05_Control_Flow.md#for_loops)。
更多关于 `for-in` 循环的信息,参见 [For 循环](./05_Control_Flow.md#for-loops)。
通过访问 `keys` 或者 `values` 属性,你也可以遍历字典的键或者值:

View File

@ -23,7 +23,7 @@ for name in names {
// Hello, Jack!
```
你也可以通过遍历一个字典来访问它的键值对。遍历字典时,字典的每项元素会以 `(key, value)` 元组的形式返回,你可以在 `for-in` 循环中使用显式的常量名称来解读 `(key, value)` 元组。下面的例子中,字典的键声明`animalName` 常量,字典的值会声明为 `legCount` 常量:
你也可以通过遍历一个字典来访问它的键值对。遍历字典时,字典的每项元素会以 `(key, value)` 元组的形式返回,你可以在 `for-in` 循环中使用显式的常量名称来解读 `(key, value)` 元组。下面的例子中,字典的键声明为 `animalName` 常量,字典的值会声明为 `legCount` 常量:
```swift
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
@ -69,7 +69,7 @@ print("\(base) to the power of \(power) is \(answer)")
这个例子计算 base 这个数的 power 次幂(本例中,是 `3``10` 次幂),从 `1``3``0` 次幂)开始做 `3` 的乘法, 进行 `10` 次,使用 `1``10` 的闭区间循环。这个计算并不需要知道每一次循环中计数器具体的值,只需要执行了正确的循环次数即可。下划线符号 `_` (替代循环中的变量)能够忽略当前值,并且不提供循环遍历时对值的访问。
在某些情况下,你可能不想使用包括两个端点的闭区间。想象一下,你在一个手表上绘制分钟的刻度线。总共 `60` 个刻度,从 `0` 分开始。使用半开区间运算符(`..<`)来表示一个左闭右开的区间。有关区间的更多信息,请参阅 [区间运算符](./02_Basic_Operators.md#range_operators)。
在某些情况下,你可能不想使用包括两个端点的闭区间。想象一下,你在一个手表上绘制分钟的刻度线。总共 `60` 个刻度,从 `0` 分开始。使用半开区间运算符(`..<`)来表示一个左闭右开的区间。有关区间的更多信息,请参阅 [区间运算符](./02_Basic_Operators.md#range-operators)。
```swift
let minutes = 60
@ -97,6 +97,8 @@ for tickMark in stride(from: 3, through: hours, by: hourInterval) {
}
```
以上示例使用 `for-in` 循环来遍历范围、数组、字典和字符串。你可以用它来遍历任何的集合,包括实现了 [Sequence](https://developer.apple.com/documentation/swift/sequence) 协议的自定义类或集合类型。
## While 循环 {#while-loops}
`while` 循环会一直运行一段语句直到条件变成 `false`。这类循环适合使用在第一次迭代前迭代次数未知的情况下。Swift 提供两种 `while` 循环形式:
@ -332,7 +334,7 @@ default:
> 注意
>
> 虽然在 Swift 中 `break` 不是必须的,但你依然可以在 case 分支中的代码执行完毕前使用 `break` 跳出,详情请参见 [Switch 语句中的 break](#break_in_a_switch_statement)。
> 虽然在 Swift 中 `break` 不是必须的,但你依然可以在 case 分支中的代码执行完毕前使用 `break` 跳出,详情请参见 [Switch 语句中的 break](#break-in-a-switch-statement)。
每一个 case 分支都*必须*包含至少一条语句。像下面这样书写代码是无效的,因为第一个 case 分支是空的:
@ -363,7 +365,7 @@ default:
// 输出“The letter A”
```
为了可读性,符合匹配可以写成多行形式,详情请参考 [复合匹配](#compound_cases)
为了可读性,符合匹配可以写成多行形式,详情请参考 [复合匹配](#compound-cases)
> 注意
>
@ -527,7 +529,7 @@ default:
- `return`
- `throw`
我们将会在下面讨论 `continue``break``fallthrough` 语句。`return` 语句将会在 [函数](./06_Functions.md) 章节讨论,`throw` 语句会在 [错误抛出](./18_Error_Handling.md#throwing_errors) 章节讨论。
我们将会在下面讨论 `continue``break``fallthrough` 语句。`return` 语句将会在 [函数](./06_Functions.md) 章节讨论,`throw` 语句会在 [错误抛出](./17_Error_Handling.md#throwing-errors) 章节讨论。
### Continue {#continue}
@ -754,7 +756,7 @@ if #available(iOS 10, macOS 10.12, *) {
以上可用性条件指定,`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`——请访问 [声明属性](../03_language_reference/07_Attributes.md) 来获取完整列表。除了指定像 iOS 8 或 macOS 10.10 的大版本号,也可以指定像 iOS 11.2.6 以及 macOS 10.13.3 的小版本号。
```swift
if #available(平台名称 版本号, ..., *) {

View File

@ -237,7 +237,7 @@ func someFunction(firstParameterName: Int, secondParameterName: Int) {
someFunction(firstParameterName: 1, secondParameterName: 2)
```
所有的参数都必须有一个独一无二的名字。虽然多个参数拥有同样的参数标签是可能的,但是一个唯一的数标签能够使你的代码更具可读性。
所有的参数都必须有一个独一无二的名字。虽然多个参数拥有同样的参数标签是可能的,但是一个唯一的数标签能够使你的代码更具可读性。
### 指定参数标签 {#specifying-argument-labels}
@ -318,7 +318,7 @@ arithmeticMean(3, 8.25, 18.75)
函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为*输入输出参数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` 关键字。一个 `输入输出参数`有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。想获取更多的关于输入输出参数的细节和相关的编译器优化,请查看 [输入输出参数](../03_language_reference/06_Declarations.md#in-out-parameters) 一节。
你只能传递变量给输入输出参数。你不能传入常量或者字面量,因为这些量是不能被修改的。当传入的参数作为输入输出参数时,需要在参数名前加 `&` 符,表示这个值可以被函数修改。

View File

@ -6,7 +6,7 @@
> 注意
>
> 如果你不熟悉捕获capturing这个概念也不用担心在 [值捕获](#capturing_values) 章节有它更详细的介绍。
> 如果你不熟悉捕获capturing这个概念也不用担心在 [值捕获](#capturing-values) 章节有它更详细的介绍。
在 [函数](./06_Functions.md) 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采用如下三种形式之一:
@ -23,7 +23,7 @@ Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进
## 闭包表达式 {#closure-expressions}
[嵌套函数](./06_Functions.md#Nested_Functions) 作为复杂函数的一部分时,它自包含代码块式的定义和命名形式在使用上带来了方便。当然,编写未完整声明和没有函数名的类函数结构代码是很有用的,尤其是在编码中涉及到函数作为参数的那些方法时。
[嵌套函数](./06_Functions.md#Nested-Functions) 作为复杂函数的一部分时,它自包含代码块式的定义和命名形式在使用上带来了方便。当然,编写未完整声明和没有函数名的类函数结构代码是很有用的,尤其是在编码中涉及到函数作为参数的那些方法时。
*闭包表达式*是一种构建内联闭包的方式,它的语法简洁。在保证不丢失它语法清晰明了的同时,闭包表达式提供了几种优化的语法简写形式。下面通过对 `sorted(by:)` 这一个案例的多次迭代改进来展示这个过程,每次迭代都使用了更加简明的方式描述了相同功能。。
@ -113,13 +113,13 @@ reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
Swift 自动为内联闭包提供了参数名称缩写功能,你可以直接通过 `$0``$1``$2` 来顺序调用闭包的参数,以此类推。
如果你在闭包表达式中使用参数名称缩写,你可以在闭包定义中省略参数列表,并且对应参数名称缩写的类型会通过函数类型进行推断。`in` 关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
如果你在闭包表达式中使用参数名称缩写,你可以在闭包定义中省略参数列表,并且对应参数名称缩写的类型会通过函数类型进行推断。闭包接受的参数的数量取决于所使用的缩写参数的最大编号。`in` 关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
```swift
reversedNames = names.sorted(by: { $0 > $1 } )
```
在这个例子中,`$0``$1` 表示闭包中第一个和第二个 `String` 类型的参数。
在这个例子中,`$0``$1` 表示闭包中第一个和第二个 `String` 类型的参数。因为 `$1` 是编号最大的缩写参数,所以可以理解为:该闭包需要两个参数。这里的 `sorted(by:)` 函数希望得到一个参数都是字符串的闭包,因此缩写参数 `$0``$1` 的类型均为 `String`
### 运算符方法 {#operator-methods}
@ -129,7 +129,7 @@ reversedNames = names.sorted(by: { $0 > $1 } )
reversedNames = names.sorted(by: >)
```
更多关于运算符方法的内容请查看 [运算符方法](./26_Advanced_Operators.md#operator_methods)。
更多关于运算符方法的内容请查看 [运算符方法](./27_Advanced_Operators.md#operator-methods)。
## 尾随闭包 {#trailing-closures}
@ -151,7 +151,7 @@ someFunctionThatTakesAClosure() {
}
```
在 [闭包表达式语法](#closure_expression_syntax) 上章节中的字符串排序闭包可以作为尾随包的形式改写在 `sorted(by:)` 方法圆括号的外面:
在 [闭包表达式语法](#closure-expression-syntax) 上章节中的字符串排序闭包可以作为尾随包的形式改写在 `sorted(by:)` 方法圆括号的外面:
```swift
reversedNames = names.sorted() { $0 > $1 }
@ -233,7 +233,7 @@ func makeIncrementer(forIncrement amount: Int) -> () -> Int {
}
```
`makeIncrementer` 返回类型为 `() -> Int`。这意味着其返回的是一个*函数*,而非一个简单类型的值。该函数在每次调用时不接受参数,只返回一个 `Int` 类型的值。关于函数返回其他函数的内容,请查看 [函数类型作为返回类型](./06_Functions.md#function_types_as_return_types)。
`makeIncrementer` 返回类型为 `() -> Int`。这意味着其返回的是一个*函数*,而非一个简单类型的值。该函数在每次调用时不接受参数,只返回一个 `Int` 类型的值。关于函数返回其他函数的内容,请查看 [函数类型作为返回类型](./06_Functions.md#function-types-as-return-types)。
`makeIncrementer(forIncrement:)` 函数定义了一个初始值为 `0` 的整型变量 `runningTotal`,用来存储当前总计数值。该值为 `incrementer` 的返回值。
@ -290,7 +290,7 @@ incrementByTen()
> 注意
>
> 如果你将闭包赋值给一个类实例的属性并且该闭包通过访问该实例或其成员而捕获了该实例你将在闭包和该实例间创建一个循环强引用。Swift 使用捕获列表来打破这种循环强引用。更多信息,请参考 [闭包引起的循环强引用](./23_Automatic_Reference_Counting.md#strong_reference_cycles_for_closures)。
> 如果你将闭包赋值给一个类实例的属性并且该闭包通过访问该实例或其成员而捕获了该实例你将在闭包和该实例间创建一个循环强引用。Swift 使用捕获列表来打破这种循环强引用。更多信息,请参考 [闭包引起的循环强引用](./24_Automatic_Reference_Counting.md#strong-reference-cycles-for-closures)。
## 闭包是引用类型 {#closures-are-reference-types}
@ -364,7 +364,7 @@ print(customersInLine.count)
// 打印出“5”
print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
// 打印出“Now serving Chris!
print(customersInLine.count)
// 打印出“4”
```
@ -397,7 +397,7 @@ serve(customer: customersInLine.remove(at: 0))
>
> 过度使用 `autoclosures` 会让你的代码变得难以理解。上下文和函数名应该能够清晰地表明求值是被延迟执行的。
如果你想让一个自动闭包可以“逃逸”,则应该同时使用 `@autoclosure``@escaping` 属性。`@escaping` 属性的讲解见上面的 [逃逸闭包](#escaping_closures)。
如果你想让一个自动闭包可以“逃逸”,则应该同时使用 `@autoclosure``@escaping` 属性。`@escaping` 属性的讲解见上面的 [逃逸闭包](#escaping-closures)。
```swift
// customersInLine i= ["Barry", "Daniella"]

View File

@ -200,7 +200,7 @@ case let .qrCode(productCode):
## 原始值 {#raw-values}
在 [关联值](#associated_values) 小节的条形码例子中,演示了如何声明存储不同类型关联值的枚举成员。作为关联值的替代选择,枚举成员可以被默认值(称为*原始值*)预填充,这些原始值的类型必须相同。
在 [关联值](#associated-values) 小节的条形码例子中,演示了如何声明存储不同类型关联值的枚举成员。作为关联值的替代选择,枚举成员可以被默认值(称为*原始值*)预填充,这些原始值的类型必须相同。
这是一个使用 ASCII 码作为原始值的枚举:
@ -273,7 +273,7 @@ let possiblePlanet = Planet(rawValue: 7)
> 注意
>
> 原始值构造器是一个可失败构造器,因为并不是每一个原始值都有与之对应的枚举成员。更多信息请参见 [可失败构造器](../chapter3/05_Declarations.html#failable_initializers)
> 原始值构造器是一个可失败构造器,因为并不是每一个原始值都有与之对应的枚举成员。更多信息请参见 [可失败构造器](../03_language_reference/06_Declarations.md#failable-initializers)
如果你试图寻找一个位置为 `11` 的行星,通过原始值构造器返回的可选 `Planet` 值将是 `nil`

View File

@ -28,7 +28,7 @@ Swift 中结构体和类有很多共同点。两者都可以:
* 析构器允许一个类实例释放任何其所被分配的资源
* 引用计数允许对一个类的多次引用
更多信息请参见 [继承](./13_Inheritance.md)、[类型转换](./18_Type_Casting.md)、[析构过程](./15_Deinitialization.md) 和 [自动引用计数](./23_Automatic_Reference_Counting.md)。
更多信息请参见 [继承](./13_Inheritance.md)、[类型转换](./18_Type_Casting.md)、[析构过程](./15_Deinitialization.md) 和 [自动引用计数](./24_Automatic_Reference_Counting.md)。
类支持的附加功能是以增加复杂性为代价的。作为一般准则,优先使用结构体,因为它们更容易理解,仅在适当或必要时才使用类。实际上,这意味着你的大多数自定义数据类型都会是结构体和枚举。更多详细的比较参见 [在结构和类之间进行选择](https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes)。
@ -243,7 +243,7 @@ if tenEighty === alsoTenEighty {
请注意,“相同”(用三个等号表示,`===`)与“等于”(用两个等号表示,`==`的不同。“相同”表示两个类类型class type的常量或者变量引用同一个类实例。“等于”表示两个实例的值“相等”或“等价”判定时要遵照设计者定义的评判标准。
当在定义你的自定义结构体和类的时候,你有义务来决定判定两个实例“相等”的标准。在章节 [等价操作符](./26_Advanced_Operators.md#equivalence_operators) 中将会详细介绍实现自定义 == 和 !== 运算符的流程。
当在定义你的自定义结构体和类的时候,你有义务来决定判定两个实例“相等”的标准。在章节 [等价操作符](./27_Advanced_Operators.md#equivalence-operators) 中将会详细介绍实现自定义 == 和 != 运算符的流程。
### 指针 {#pointers}

View File

@ -6,11 +6,12 @@
另外,还可以定义属性观察器来监控属性值的变化,以此来触发自定义的操作。属性观察器可以添加到类本身定义的存储属性上,也可以添加到从父类继承的属性上。
你也可以利用属性包装器来复用多个属性的 getter 和 setter 中的代码。
## 存储属性 {#stored-properties}
简单来说,一个存储属性就是存储在特定类或结构体实例里的一个常量或变量。存储属性可以是*变量存储属性*(用关键字 `var` 定义),也可以是*常量存储属性*(用关键字 `let` 定义)。
可以在定义存储属性的时候指定默认值,请参考 [默认构造器](./14_Initialization.md#default_initializers) 一节。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值,请参考 [构造过程中常量属性的修改](./14_Initialization.md#assigning_constant_properties_during_initialization) 一节。
可以在定义存储属性的时候指定默认值,请参考 [默认构造器](./14_Initialization.md#default-initializers) 一节。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值,请参考 [构造过程中常量属性的修改](./14_Initialization.md#assigning-constant-properties-during-initialization) 一节。
下面的例子定义了一个名为 `FixedLengthRange` 的结构体,该结构体用于描述整数的区间,且这个范围值在被创建后不能被修改。
@ -98,7 +99,7 @@ print(manager.importer.fileName)
### 存储属性和实例变量 {#stored-properties-and-instance-variables}
如果有过 Objective-C 经验,应该知道 Objective-C 为类实例存储值和引用提供两种方法。除了属性之外,还可以使用实例变量作为一个备份存储将变量值赋值给属性。
如果有过 Objective-C 经验,应该知道 Objective-C 为类实例存储值和引用提供两种方法。除了属性之外,还可以使用实例变量作为一个备份存储将变量值赋值给属性。
Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的备份存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。属性的全部信息——包括命名、类型和内存管理特征——作为类型定义的一部分,都定义在一个地方。
@ -224,7 +225,12 @@ print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。
你可以为除了延时加载存储属性之外的其他存储属性添加属性观察器,你也可以在子类中通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。你不必为非重写的计算属性添加属性观察器,因为你可以直接通过它的 setter 监控和响应值的变化。属性重写请参考 [重写](./13_Inheritance.md#overriding)。
你可以在以下位置添加属性观察器:
* 自定义的存储属性
* 继承的存储属性
* 继承的计算属性
对于继承的属性,你可以在子类中通过重写属性的方式为它添加属性观察器。对于自定义的计算属性来说,使用它的 setter 监控和响应值的变化,而不是尝试创建观察器。属性重写请参考 [重写](./13_Inheritance.md#overriding)。
可以为属性添加其中一个或两个观察器:
@ -239,7 +245,7 @@ print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
>
> 在父类初始化方法调用之后,在子类构造器中给父类的属性赋值时,会调用父类属性的 `willSet``didSet` 观察器。而在父类初始化方法调用之前,给子类的属性赋值时不会调用子类属性的观察器。
>
> 有关构造器代理的更多信息,请参考 [值类型的构造器代理](./14_Initialization.md#initializer_delegation_for_value_types) 和 [类的构造器代理](./14_Initialization.md#initializer_delegation_for_class_types)。
> 有关构造器代理的更多信息,请参考 [值类型的构造器代理](./14_Initialization.md#initializer-delegation-for-value-types) 和 [类的构造器代理](./14_Initialization.md#initializer-delegation-for-class-types)。
下面是一个 `willSet``didSet` 实际运用的例子,其中定义了一个名为 `StepCounter` 的类,用来统计一个人步行时的总步数。这个类可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。
@ -278,7 +284,247 @@ stepCounter.totalSteps = 896
> 注意
>
> 如果将带有观察器的属性通过 in-out 方式传入函数,`willSet``didSet` 也会调用。这是因为 in-out 参数采用了拷入拷出内存模式:即在函数内部使用的是参数的 copy函数结束后又对参数重新赋值。关于 in-out 参数详细的介绍,请参考 [输入输出参数](../chapter3/05_Declarations.html#in-out_parameters)
> 如果将带有观察器的属性通过 in-out 方式传入函数,`willSet``didSet` 也会调用。这是因为 in-out 参数采用了拷入拷出内存模式:即在函数内部使用的是参数的 copy函数结束后又对参数重新赋值。关于 in-out 参数详细的介绍,请参考 [输入输出参数](../03_language_reference/06_Declarations.md#in-out-parameters)
## 属性包装器 {#property-wrappers}
属性包装器在管理属性如何存储和定义属性的代码之间添加了一个分隔层。举例来说,如果你的属性需要线程安全性检查或者需要在数据库中存储它们的基本数据,那么必须给每个属性添加同样的逻辑代码。当使用属性包装器时,你只需在定义属性包装器时编写一次管理代码,然后应用到多个属性上来进行复用。
定义一个属性包装器,你需要创建一个定义 `wrappedValue` 属性的结构体、枚举或者类。在下面的代码中,`TwelveOrLess` 结构体确保它包装的值始终是小于等于 12 的数字。如果要求它存储一个更大的数字,它则会存储 12 这个数字。
```swift
@propertyWrapper
struct TwelveOrLess {
private var number: Int
init() { self.number = 0 }
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
}
```
这个 setter 确保新值小于 12而且返回被存储的值。
> 注意
>
> 上面例子以 `private` 的方式声明 `number` 变量,这使得 `number` 仅在 `TwelveOrLess` 的实现中使用。写在其他地方的代码通过使用 `wrappedValue` 的 getter 和 setter 来获取这个值,但不能直接使用 `number`。有关 `private` 的更多信息,请参考 [访问控制](./26_Access_Control.md)
通过在属性之前写上包装器名称作为特性的方式,你可以把一个包装器应用到一个属性上去。这里有个存储小矩形的结构体。通过 `TwelveOrLess` 属性包装器实现类似(挺随意的)对“小”的定义。
```swift
struct SmallRectangle {
@TwelveOrLess var height: Int
@TwelveOrLess var width: Int
}
var rectangle = SmallRectangle()
print(rectangle.height)
// 打印 "0"
rectangle.height = 10
print(rectangle.height)
// 打印 "10"
rectangle.height = 24
print(rectangle.height)
// 打印 "12"
```
`height``width` 属性从 `TwelveOrLess` 的定义中获取它们的初始值。该定义把 `TwelveOrLess.number` 设置为 0。把数字 10 存进 `rectangle.height` 中的操作能成功,是因为数字 10 很小。尝试存储 24 的操作实际上存储的值为 12这是因为对于这个属性的 setter 的规则来说24 太大了。
当你把一个包装器应用到一个属性上时,编译器将合成提供包装器存储空间和通过包装器访问属性的代码。(属性包装器只负责存储被包装值,所以没有合成这些代码。)不利用这个特性语法的情况下,你可以写出使用属性包装器行为的代码。举例来说,这是先前代码清单中的 `SmallRectangle` 的另一个版本。这个版本将其属性明确地包装在 `TwelveOrLess` 结构体中,而不是把 `@TwelveOrLess` 作为特性写下来:
```swift
struct SmallRectangle {
private var _height = TwelveOrLess()
private var _width = TwelveOrLess()
var height: Int {
get { return _height.wrappedValue }
set { _height.wrappedValue = newValue }
}
var width: Int {
get { return _width.wrappedValue }
set { _width.wrappedValue = newValue }
}
}
```
`_height``_width` 属性存着这个属性包装器的一个实例,即 `TwelveOrLess``height``width` 的 getter 和 setter 把对 `wrappedValue` 属性的访问包装起来。
### 设置被包装属性的初始值 {#setting-initial-values-for-wrapped-properties}
上面例子中的代码通过在 `TwelveOrLess` 的定义中赋予 `number` 一个初始值来设置被包装属性的初始值。使用这个属性包装器的代码没法为被 `TwelveOrLess` 包装的属性指定其他初始值。举例来说,`SmallRectangle` 的定义没法给 `height` 或者 `width` 一个初始值。为了支持设定一个初始值或者其他自定义操作,属性包装器需要添加一个构造器。这是 `TwelveOrLess` 的扩展版本,称为 `SmallNumber``SmallNumber` 定义了能设置被包装值和最大值的构造器:
```swift
@propertyWrapper
struct SmallNumber {
private var maximum: Int
private var number: Int
var wrappedValue: Int {
get { return number }
set { number = min(newValue, maximum) }
}
init() {
maximum = 12
number = 0
}
init(wrappedValue: Int) {
maximum = 12
number = min(wrappedValue, maximum)
}
init(wrappedValue: Int, maximum: Int) {
self.maximum = maximum
number = min(wrappedValue, maximum)
}
}
```
`SmallNumber` 的定义包括三个构造器——`init()``init(wrappedValue:)``init(wrappedValue:maximum:)`——下面的示例使用这三个构造器来设置被包装值和最大值。有关构造过程和构造器语法的更多信息,请参考 [构造过程](./14_Initialization.md)。
当你把包装器应用于属性且没有设定初始值时Swift 使用 `init()` 构造器来设置包装器。举个例子:
```swift
struct ZeroRectangle {
@SmallNumber var height: Int
@SmallNumber var width: Int
}
var zeroRectangle = ZeroRectangle()
print(zeroRectangle.height, zeroRectangle.width)
// 打印 "0 0"
```
调用 `SmallNumber()` 来创建包装 `height``width``SmallNumber` 的实例。构造器内部的代码使用默认值 0 和 12 设置初始的被包装值和初始的最大值。像之前使用在 `SmallRectangle` 中使用 `TwelveOrLess` 的例子,这个属性包装器仍然提供所有的初始值。与这个例子不同的是,`SmallNumber` 也支持把编写这些初始值作为声明属性的一部分。
当你为属性指定初始值时Swift 使用 `init(wrappedValue:)` 构造器来设置包装器。举个例子:
```swift
struct UnitRectangle {
@SmallNumber var height: Int = 1
@SmallNumber var width: Int = 1
}
var unitRectangle = UnitRectangle()
print(unitRectangle.height, unitRectangle.width)
// 打印 "1 1"
```
当你对一个被包装的属性写下 `= 1` 时,这被转换为调用 `init(wrappedValue:)` 构造器。调用 `SmallNumber(wrappedValue: 1)`来创建包装 `height``width``SmallNumber` 的实例。构造器使用此处指定的被包装值,且使用的默认最大值为 12。
当你在自定义特性后面把实参写在括号里时Swift 使用接受这些实参的构造器来设置包装器。举例来说如果你提供初始值和最大值Swift 使用 `init(wrappedValue:maximum:)` 构造器:
```swift
struct NarrowRectangle {
@SmallNumber(wrappedValue: 2, maximum: 5) var height: Int
@SmallNumber(wrappedValue: 3, maximum: 4) var width: Int
}
var narrowRectangle = NarrowRectangle()
print(narrowRectangle.height, narrowRectangle.width)
// 打印 "2 3"
narrowRectangle.height = 100
narrowRectangle.width = 100
print(narrowRectangle.height, narrowRectangle.width)
// 打印 "5 4"
```
调用 `SmallNumber(wrappedValue: 2, maximum: 5)` 来创建包装 `height``SmallNumber` 的一个实例。调用 `SmallNumber(wrappedValue: 3, maximum: 4)` 来创建包装 `width``SmallNumber` 的一个实例。
通过将实参包含到属性包装器中,你可以设置包装器的初始状态,或者在创建包装器时传递其他的选项。这种语法是使用属性包装器最通用的方法。你可以为这个属性提供任何所需的实参,且它们将被传递给构造器。
当包含属性包装器实参时你也可以使用赋值来指定初始值。Swift 将赋值视为 `wrappedValue` 参数,且使用接受被包含的实参的构造器。举个例子:
```swift
struct MixedRectangle {
@SmallNumber var height: Int = 1
@SmallNumber(maximum: 9) var width: Int = 2
}
var mixedRectangle = MixedRectangle()
print(mixedRectangle.height)
// 打印 "1"
mixedRectangle.height = 20
print(mixedRectangle.height)
// 打印 "12"
```
调用 `SmallNumber(wrappedValue: 1)` 来创建包装 `height``SmallNumber` 的一个实例,这个实例使用默认最大值 12。调用 `SmallNumber(wrappedValue: 2, maximum: 9)` 来创建包装 `width``SmallNumber` 的一个实例。
### 从属性包装器中呈现一个值 {#projecting-a-value-from-a-property-wrapper}
除了被包装值,属性包装器可以通过定义被呈现值暴露出其他功能。举个例子,管理对数据库的访问的属性包装器可以在它的被呈现值上暴露出 `flushDatabaseConnection()` 方法。除了以货币符号(\$)开头,被呈现值的名称和被包装值是一样的。因为你的代码不能够定义以 $ 开头的属性,所以被呈现值永远不会与你定义的属性有冲突。
在之前 `SmallNumber` 的例子中,如果你尝试把这个属性设置为一个很大的数值,属性包装器会在存储这个数值之前调整这个数值。以下的代码把被呈现值添加到 `SmallNumber` 结构体中来追踪在存储新值之前属性包装器是否为这个属性调整了新值。
```swift
@propertyWrapper
struct SmallNumber {
private var number: Int
var projectedValue: Bool
init() {
self.number = 0
self.projectedValue = false
}
var wrappedValue: Int {
get { return number }
set {
if newValue > 12 {
number = 12
projectedValue = true
} else {
number = newValue
projectedValue = false
}
}
}
}
struct SomeStructure {
@SmallNumber var someNumber: Int
}
var someStructure = SomeStructure()
someStructure.someNumber = 4
print(someStructure.$someNumber)
// 打印 "false"
someStructure.someNumber = 55
print(someStructure.$someNumber)
// 打印 "true"
```
写下 `someStructure.$someNumber` 即可访问包装器的被呈现值。在存储一个比较小的数值时,如 4 `someStructure.$someNumber` 的值为 `false`。但是,在尝试存储一个较大的数值时,如 55 ,被呈现值变为 `true`
属性包装器可以返回任何类型的值作为它的被呈现值。在这个例子里,属性包装器要暴露的信息是:那个数值是否被调整过,所以它暴露出布尔型值来作为它的被呈现值。需要暴露出更多信息的包装器可以返回其他数据类型的实例,或者可以返回自身来暴露出包装器的实例,并把其作为它的被呈现值。
当从类型的一部分代码中访问被呈现值,例如属性 getter 或实例方法,你可以在属性名称之前省略 `self.`,就像访问其他属性一样。以下示例中的代码用 `$height``$width` 引用包装器 `height``width` 的被呈现值:
```swift
enum Size {
case small, large
}
struct SizedRectangle {
@SmallNumber var height: Int
@SmallNumber var width: Int
mutating func resize(to size: Size) -> Bool {
switch size {
case .small:
height = 10
width = 20
case .large:
height = 100
width = 100
}
return $height || $width
}
}
```
因为属性包装器语法只是具有 getter 和 setter 的属性的语法糖,所以访问 `height``width` 的行为与访问任何其他属性的行为相同。举个例子,`resize(to:)` 中的代码使用它们的属性包装器来访问 `height``width`。如果调用 `resize(to: .large)``.large` 的 switch case 分支语句把矩形的高度和宽度设置为 100。属性包装器防止这些属性的值大于 12且把被呈现值设置成为 `true` 来记下它调整过这些值的事实。在 `resize(to:)` 的最后,返回语句检查 `$height``$width` 来确认是否属性包装器调整过 `height``width`
## 全局变量和局部变量 {#global-and-local-variables}
@ -290,7 +536,7 @@ stepCounter.totalSteps = 896
> 注意
>
> 全局的常量或变量都是延迟计算的,跟 [延时加载存储属性](#lazy_stored_properties) 相似,不同的地方在于,全局的常量或变量不需要标记 `lazy` 修饰符。
> 全局的常量或变量都是延迟计算的,跟 [延时加载存储属性](#lazy-stored-properties) 相似,不同的地方在于,全局的常量或变量不需要标记 `lazy` 修饰符。
>
> 局部范围的常量和变量从不延迟计算。

View File

@ -47,7 +47,7 @@ counter.reset()
// 计数值现在是0
```
函数参数可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用),详情参见 [指定外部参数名](./06_Functions.md#specifying_external_parameter_names)。方法参数也一样,因为方法就是函数,只是这个函数与某个类型相关联了。
函数参数可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用),详情参见 [指定外部参数名](./06_Functions.md#specifying-external-parameter-names)。方法参数也一样,因为方法就是函数,只是这个函数与某个类型相关联了。
### self 属性 {#the-self-property}
@ -107,7 +107,7 @@ print("The point is now at (\(somePoint.x), \(somePoint.y))")
上面的 `Point` 结构体定义了一个可变方法 `moveByxy :)` 来移动 `Point` 实例到给定的位置。该方法被调用时修改了这个点,而不是返回一个新的点。方法定义时加上了 `mutating` 关键字,从而允许修改属性。
注意不能在结构体类型的常量a constant of structure type上调用可变方法因为其属性不能被改变即使属性是变量属性详情参见 [常量结构体的存储属性](./10_Properties.md#stored_properties_of_constant_structure_instances)
注意不能在结构体类型的常量a constant of structure type上调用可变方法因为其属性不能被改变即使属性是变量属性详情参见 [常量结构体的存储属性](./10_Properties.md#stored-properties-of-constant-structure-instances)
```swift
let fixedPoint = Point(x: 3.0, y: 3.0)
@ -213,7 +213,7 @@ struct LevelTracker {
除了类型属性和类型方法,`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` 属性,更多关于属性信息,请参考 [特性](../03_language_reference/07_Attributes.md) 章节。
下面,`Player` 类使用 `LevelTracker` 来监测和更新每个玩家的发展进度:

View File

@ -2,11 +2,11 @@
*下标*可以定义在类、结构体和枚举中,是访问集合、列表或序列中元素的快捷方式。可以使用下标的索引,设置和获取值,而不需要再调用对应的存取方法。举例来说,用下标访问一个 `Array` 实例中的元素可以写作 `someArray[index]`,访问 `Dictionary` 实例中的元素可以写作 `someDictionary[key]`
一个类型可以定义多个下标,通过不同索引类型进行重载。下标不限于一维,你可以定义具有多个入参的下标满足自定义类型的需求。
一个类型可以定义多个下标,通过不同索引类型进行对应的重载。下标不限于一维,你可以定义具有多个入参的下标满足自定义类型的需求。
## 下标语法 {#subscript-syntax}
下标允许你通过在实例名称后面的方括号中传入一个或者多个索引值来对实例进行存取。语法类似于实例方法语法和计算型属性语法的混合。与定义实例方法类似,定义下标使用 `subscript` 关键字,指定一个或多个输入参数和返回类型与实例方法不同的是,下标可以设定为读写或只读。这种行为由 getter 和 setter 实现,有点类似计算型属性:
下标允许你通过在实例名称后面的方括号中传入一个或者多个索引值来对实例进行查询。它的语法类似于实例方法语法和计算型属性语法定义下标使用 `subscript` 关键字,与定义实例方法类似,都是指定一个或多个输入参数和一个返回类型与实例方法不同的是,下标可以设定为读写或只读。这种行为由 getter 和 setter 实现,类似计算型属性:
```swift
subscript(index: Int) -> Int {
@ -19,9 +19,9 @@ subscript(index: Int) -> Int {
}
```
`newValue` 的类型和下标的返回类型相同。如同计算型属性,可以不指定 setter 的参数(`newValue`。如果不指定参数setter 会提供一个名为 `newValue` 的默认参数。
`newValue` 的类型和下标操作的返回类型相同。如同计算型属性,可以不指定 setter 的参数(`newValue`。如果不指定参数setter 会提供一个名为 `newValue` 的默认参数。
如同只读计算型属性,可以省略只读下标的 `get` 关键字:
如同只读计算型属性,对于只读下标的声明,你可以通过省略 `get` 关键字和对应的大括号组来进行简写
```swift
subscript(index: Int) -> Int {
@ -29,7 +29,7 @@ subscript(index: Int) -> Int {
}
```
下面代码演示了只读下标的实现,这里定义了一个 `TimesTable` 结构体,用来表示传入整数的乘法表:
下面代码演示了只读下标的实现,这里定义了一个 `TimesTable` 结构体,用来表示对应整数的乘法表:
```swift
struct TimesTable {
@ -45,7 +45,7 @@ print("six times three is \(threeTimesTable[6])")
在上例中,创建了一个 `TimesTable` 实例,用来表示整数 `3` 的乘法表。数值 `3` 被传递给结构体的构造函数,作为实例成员 `multiplier` 的值。
你可以通过下标访问 `threeTimesTable` 实例,例如上面演示的 `threeTimesTable[6]`。这条语句查询了 `3` 的乘法表中的第六个元素,返回 `3``6` 倍即 `18`
你可以通过下标访问 `threeTimesTable` 实例,例如上面演示的 `threeTimesTable[6]`。这条语句查询了乘法表中 `3` 的第六个元素,返回 `3``6` 倍即 `18`
> 注意
>
@ -53,9 +53,9 @@ print("six times three is \(threeTimesTable[6])")
## 下标用法 {#subscript-usage}
下标的确切含义取决于使用场景。下标通常作为访问集合,列表或序列中元素的快捷方式。你可以针对自己特定的类或结构体功能来自由地以最恰当的方式实现下标。
下标的确切含义取决于使用场景。下标通常作为访问集合,列表或序列中元素的快捷方式。你可以针对自己特定的类或结构体功能来以最恰当的方式实现下标。
例如Swift 的 `Dictionary` 类型实现下标用于对实例中储存的值进行存取操作。为字典设值时,在下标中使用和字典的键类型相同的键,并把一个和字典的值类型相同的值赋给这个下标:
例如Swift 的 `Dictionary` 类型实现下标用于对实例中储存的值进行存取操作。为字典设值时,在下标中使用和字典的键类型相同的键,并把一个和字典的值类型相同的值赋给这个下标:
```swift
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
@ -64,17 +64,19 @@ numberOfLegs["bird"] = 2
上例定义一个名为 `numberOfLegs` 的变量,并用一个包含三对键值的字典字面量初始化它。`numberOfLegs` 字典的类型被推断为 `[String: Int]`。字典创建完成后,该例子通过下标将 `String` 类型的键 `bird``Int` 类型的值 `2` 添加到字典中。
更多关于 `Dictionary` 下标的信息请参考 [读取和修改字典](./04_Collection_Types.md#accessing_and_modifying_a_dictionary)。
更多关于 `Dictionary` 下标的信息请参考 [读取和修改字典](./04_Collection_Types.md#accessing-and-modifying-a-dictionary)。
> 注意
>
> Swift 的 `Dictionary` 类型的下标接受并返回可选类型的值。上例中的 `numberOfLegs` 字典通过下标返回的是一个 `Int?` 或者说“可选的 int”。`Dictionary` 类型之所以如此实现下标,是因为不是每个键都有对应的值,同时这也提供了一种通过键删除对应值的方式,只需将键对应的值赋值为 `nil` 即可。
> Swift 的 `Dictionary` 类型的下标接受并返回_可选_类型的值。上例中的 `numberOfLegs` 字典通过下标返回的是一个 `Int?` 或者说“可选的 int”。`Dictionary` 类型之所以如此实现下标,是因为不是每个键都有对应的值,同时这也提供了一种通过键删除对应值的方式,只需将键对应的值赋值为 `nil` 即可。
## 下标选项 {#subscript-options}
下标可以接受任意数量的入参,并且这些入参可以是任类型。下标的返回值也可以是任意类型。下标可以使用可变参数,并且可以提供默认参数数值,但是不能使用输入输出参数。
下标可以接受任意数量的入参,并且这些入参可以是任类型。下标的返回值也可以是任意类型。
与函数一样,下标可以接受不同数量的参数,并且为这些参数提供默认值,如在[可变参数](./06_Functions.md#variadic-parameters) 和 [默认参数值](./06_Functions.md#default-parameter-values) 中所述。但是,与函数不同的是,下标不能使用 in-out 参数。
一个类或结构体可以根据自身需要提供多个下标实现,使用下标时将通过入参的数量和类型进行区分,自动匹配合适的下标,这就是*下标的重载*。
一个类或结构体可以根据自身需要提供多个下标实现,使用下标时将通过入参的数量和类型进行区分,自动匹配合适的下标。它通常被称为*下标的重载*。
虽然接受单一入参的下标是最常见的,但也可以根据情况定义接受多个入参的下标。例如下例定义了一个 `Matrix` 结构体,用于表示一个 `Double` 类型的二维矩阵。`Matrix` 结构体的下标接受两个整型参数:
@ -103,15 +105,15 @@ struct Matrix {
}
```
`Matrix` 提供了一个接受两个入参的构造方法,入参分别是 `rows``columns`,创建了一个足够容纳 `rows * columns``Double` 类型的值的数组。通过传入数组长度和初始值 `0.0` 到数组的构造器,将矩阵中每个位置的值初始化为 `0.0`。关于数组的这种构造方法请参考 [创建一个带有默认值的数组](./04_Collection_Types.md#creating_an_array_with_a_default_value)。
`Matrix` 提供了一个接受两个入参的构造方法,入参分别是 `rows``columns`,创建了一个足够容纳 `rows * columns``Double` 类型的值的数组。通过传入数组长度和初始值 `0.0` 到数组的构造器,将矩阵中每个位置的值初始化为 `0.0`。关于数组的这种构造方法请参考 [创建一个带有默认值的数组](./04_Collection_Types.md#creating-an-array-with-a-default-value)。
你可以通过传入合适的 `row``column` 的数量来构造一个新的 `Matrix` 实例:
你可以通过传入合适的 `row``column` 数值来构造一个新的 `Matrix` 实例:
```swift
var matrix = Matrix(rows: 2, columns: 2)
```
上例中创建了一个 `Matrix` 实例来表示两行两列的矩阵。该 `Matrix` 实例的 `grid` 数组按照从左上到右下的阅读顺序将矩阵扁平化存储:
上例中创建了一个两行两列的 `Matrix` 实例。该 `Matrix` 实例的 `grid` 数组按照从左上到右下的阅读顺序将矩阵扁平化存储:
![](https://docs.swift.org/swift-book/_images/subscriptMatrix01_2x.png)
@ -139,18 +141,18 @@ func indexIsValid(row: Int, column: Int) -> Bool {
```swift
let someValue = matrix[2, 2]
// 断言将会触发,因为 [2, 2] 已经超过了 matrix 的范围
```
## 类型下标{#type-subscripts}
正如上节所述,实例下标是在特定类型的一个实例上调用的下标。你也可以定义一种在这个类型身上调用的下标。这种下标的类型被称作类型下标。你可以通过在 `subscript` 关键字之前写下 `static` 关键字的方式来表示一个类型下标。类可以使用 `class` 关键字来允许子类重写父类中对那个下标的实现。下面的例子展示了如何定义和调用一个类型下标:
```
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
static subscript(n: Int) -> Planet {
return Planet(rawValue: n)!
}
}
let mars = Planet[4]
print(mars)
```
```
## 类型下标{#type-subscripts}
正如上节所述,实例下标是在特定类型的一个实例上调用的下标。你也可以定义一种在这个类型身上调用的下标。这种下标被称作_类型下标_。你可以通过在 `subscript` 关键字之前写下 `static` 关键字的方式来表示一个类型下标。类类型可以使用 `class` 关键字来代替 `static`,它允许子类重写父类中对那个下标的实现。下面的例子展示了如何定义和调用一个类型下标:
```
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
static subscript(n: Int) -> Planet {
return Planet(rawValue: n)!
}
}
let mars = Planet[4]
print(mars)
```

View File

@ -57,7 +57,7 @@ class SomeClass: SomeSuperclass {
}
```
下一个例子,定义了一个叫 `Bicycle` 的子类,继承自`Vehicle`
下一个例子,定义了一个叫 `Bicycle` 的子类,继承自`Vehicle`
```swift
class Bicycle: Vehicle {
@ -111,7 +111,7 @@ print("Tandem: \(tandem.description)")
如果要重写某个特性,你需要在重写定义的前面加上 `override` 关键字。这么做,就表明了你是想提供一个重写版本,而非错误地提供了一个相同的定义。意外的重写行为可能会导致不可预知的错误,任何缺少 `override` 关键字的重写都会在编译时被认定为错误。
`override` 关键字会提醒 Swift 编译器去检查该类的超类(或其中一个类)是否有匹配重写版本的声明。这个检查可以确保你的重写定义是正确的。
`override` 关键字会提醒 Swift 编译器去检查该类的超类(或其中一个类)是否有匹配重写版本的声明。这个检查可以确保你的重写定义是正确的。
### 访问超类的方法,属性及下标 {#accessing-superclass-methods-properties-and-subscripts}
@ -184,7 +184,7 @@ print("Car: \(car.description)")
#### 重写属性观察器 {#overriding-property-observers}
你可以通过重写属性为一个继承来的属性添加属性观察器。这样一来,无论被继承属性原本是如何实现的,当其属性值发生改变时,你就会被通知到。关于属性观察器的更多内容,请看 [属性观察器](../chapter2/10_Properties.html#property_observers)。
你可以通过重写属性为一个继承来的属性添加属性观察器。这样一来,无论被继承属性原本是如何实现的,当其属性值发生改变时,你就会被通知到。关于属性观察器的更多内容,请看 [属性观察器](../02_language_guide/10_Properties.md#property-observers)。
> 注意
>

View File

@ -14,7 +14,7 @@
> 注意
>
> 当你为存储型属性分配默认值或者在构造器中设置初始值时,它们的值是被直接设置的,不会触发任何属性观察者。
> 当你为存储型属性分配默认值或者在构造器中设置初始值时,它们的值是被直接设置的,不会触发任何属性观察者。
### 构造器 {#initializers}
@ -131,7 +131,7 @@ let veryGreen = Color(0.0, 1.0, 0.0)
如果你不希望构造器的某个形参使用实参标签,可以使用下划线(`_`)来代替显式的实参标签来重写默认行为。
下面是之前 [形参的构造过程](#initialization_parameters) 中 `Celsius` 例子的扩展,多了一个用已经的摄氏表示的 `Double` 类型值来创建新的 `Celsius` 实例的额外构造器:
下面是之前 [形参的构造过程](#initialization-parameters) 中 `Celsius` 例子的扩展,多了一个用已经的摄氏表示的 `Double` 类型值来创建新的 `Celsius` 实例的额外构造器:
```swift
struct Celsius {
@ -258,7 +258,7 @@ print(zeroByZero.width, zeroByZero.height)
构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为*构造器代理*,它能避免多个构造器间的代码重复。
构造器代理的实现规则和形式在值类型和类类型中有所不同。值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给自己的其它构造器。类则不同,它可以继承自其它类(请参考 [继承](./13_Inheritance.md))。这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。这些责任将在后续章节 [类的继承和构造过程](#class_inheritance_and_initialization) 中介绍。
构造器代理的实现规则和形式在值类型和类类型中有所不同。值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给自己的其它构造器。类则不同,它可以继承自其它类(请参考 [继承](./13_Inheritance.md))。这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。这些责任将在后续章节 [类的继承和构造过程](#class-inheritance-and-initialization) 中介绍。
对于值类型,你可以使用 `self.init` 在自定义的构造器中引用相同类型中的其它构造器。并且你只能在构造器内部调用 `self.init`
@ -328,7 +328,7 @@ let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
> 注意
>
> 如果你想用另外一种不需要自己定义 `init()``init(origin:size:)` 的方式来实现这个例子,请参考 [扩展](./21_Extensions.md)。
> 如果你想用另外一种不需要自己定义 `init()``init(origin:size:)` 的方式来实现这个例子,请参考 [扩展](./20_Extensions.md)。
## 类的继承和构造过程 {#class-inheritance-and-initialization}
@ -342,7 +342,7 @@ Swift 为类类型提供了两种构造器来确保实例中所有存储型属
类倾向于拥有极少的指定构造器,普遍的是一个类只拥有一个指定构造器。指定构造器像一个个“漏斗”放在构造过程发生的地方,让构造过程沿着父类链继续往上进行。
每一个类都必须至少拥有一个指定构造器。在某些情况下,许多类通过继承了父类中的指定构造器而满足了这个条件。具体内容请参考后续章节 [构造器的自动继承](#automatic_initializer_inheritance)。
每一个类都必须至少拥有一个指定构造器。在某些情况下,许多类通过继承了父类中的指定构造器而满足了这个条件。具体内容请参考后续章节 [构造器的自动继承](#automatic-initializer-inheritance)。
*便利构造器*是类中比较次要的、辅助型的构造器。你可以定义便利构造器来调用同一个类中的指定构造器,并为部分形参提供默认值。你也可以定义便利构造器来创建一个特殊用途或特定输入值的实例。
@ -479,11 +479,11 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
> 注意
>
> 父类的构造器仅会在安全和适当的某些情况下被继承。具体内容请参考后续章节 [构造器的自动继承](#automatic_initializer_inheritance)。
> 父类的构造器仅会在安全和适当的某些情况下被继承。具体内容请参考后续章节 [构造器的自动继承](#automatic-initializer-inheritance)。
假如你希望自定义的子类中能提供一个或多个跟父类相同的构造器,你可以在子类中提供这些构造器的自定义实现。
当你在编写一个和父类中指定构造器相匹配的子类构造器时,你实际上是在重写父类的这个指定构造器。因此,你必须在定义子类构造器时带上 `override` 修饰符。即使你重写的是系统自动提供的默认构造器,也需要带上 `override` 修饰符,具体内容请参考 [默认构造器](#default_initializers)。
当你在编写一个和父类中指定构造器相匹配的子类构造器时,你实际上是在重写父类的这个指定构造器。因此,你必须在定义子类构造器时带上 `override` 修饰符。即使你重写的是系统自动提供的默认构造器,也需要带上 `override` 修饰符,具体内容请参考 [默认构造器](#default-initializers)。
正如重写属性,方法或者是下标,`override` 修饰符会让编译器去检查父类中是否有相匹配的指定构造器,并验证构造器参数是否被按预想中被指定。
@ -491,7 +491,7 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
>
> 当你重写一个父类的指定构造器时,你总是需要写 `override` 修饰符,即使是为了实现子类的便利构造器。
相反,如果你编写了一个和父类便利构造器相匹配的子类构造器,由于子类不能直接调用父类的便利构造器(每个规则都在上文 [类的构造器代理规则](#initializer_delegation_for_class_types) 有所描述),因此,严格意义上来讲,你的子类并未对一个父类构造器提供重写。最后的结果就是,你在子类中“重写”一个父类便利构造器时,不需要加 `override` 修饰符。
相反,如果你编写了一个和父类便利构造器相匹配的子类构造器,由于子类不能直接调用父类的便利构造器(每个规则都在上文 [类的构造器代理规则](#initializer-delegation-for-class-types) 有所描述),因此,严格意义上来讲,你的子类并未对一个父类构造器提供重写。最后的结果就是,你在子类中“重写”一个父类便利构造器时,不需要加 `override` 修饰符。
在下面的例子中定义了一个叫 `Vehicle` 的基类。基类中声明了一个存储型属性 `numberOfWheels`,它是默认值为 `Int` 类型的 `0``numberOfWheels` 属性用在一个描述车辆特征 `String` 类型为 `descrpiption` 的计算型属性中:
@ -504,7 +504,7 @@ class Vehicle {
}
```
`Vehicle` 类只为存储型属性提供默认值,也没有提供自定义构造器。因此,它会自动获得一个默认构造器,具体内容请参考 [默认构造器](#default_initializers)。默认构造器(如果有的话)总是类中的指定构造器,可以用于创建 `numberOfWheels``0``Vehicle` 实例:
`Vehicle` 类只为存储型属性提供默认值,也没有提供自定义构造器。因此,它会自动获得一个默认构造器,具体内容请参考 [默认构造器](#default-initializers)。默认构造器(如果有的话)总是类中的指定构造器,可以用于创建 `numberOfWheels``0``Vehicle` 实例:
```swift
let vehicle = Vehicle()
@ -642,11 +642,11 @@ class RecipeIngredient: Food {
![RecipeIngredient 构造器](https://docs.swift.org/swift-book/_images/initializersExample02_2x.png)
`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)` 使用了跟 `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` 会自动继承父类的所有便利构造器。

View File

@ -4,7 +4,7 @@
## 析构过程原理 {#how-deinitialization-works}
Swift 会自动释放不再需要的实例以释放资源。如 [自动引用计数](./23_Automatic_Reference_Counting.md) 章节中所讲述Swift 通过*自动引用计数ARC)* 处理实例的内存管理。通常当你的实例被释放时不需要手动地去清理。但是,当使用自己的资源时,你可能需要进行一些额外的清理。例如,如果创建了一个自定义的类来打开一个文件,并写入一些数据,你可能需要在类实例被释放之前手动去关闭该文件。
Swift 会自动释放不再需要的实例以释放资源。如 [自动引用计数](./24_Automatic_Reference_Counting.md) 章节中所讲述Swift 通过*自动引用计数ARC)* 处理实例的内存管理。通常当你的实例被释放时不需要手动地去清理。但是,当使用自己的资源时,你可能需要进行一些额外的清理。例如,如果创建了一个自定义的类来打开一个文件,并写入一些数据,你可能需要在类实例被释放之前手动去关闭该文件。
在类的定义中,每个类最多只能有一个析构器,而且析构器不带任何参数和圆括号,如下所示:

View File

@ -6,15 +6,15 @@
>
> Swift 的可选链式调用和 Objective-C 中向 `nil` 发送消息有些相像,但是 Swift 的可选链式调用可以应用于任意类型,并且能检查调用是否成功。
## 使用可选链式调用代替强制展开 {#optional-chaining-as-an-alternative-to-forced-unwrapping}
## 使用可选链式调用代替强制解包 {#optional-chaining-as-an-alternative-to-forced-unwrapping}
通过在想调用的属性、方法,或下标的可选值后面放一个问号(`?`),可以定义一个可选链。这一点很像在可选值后面放一个叹号(`!`)来强制展开它的值。它们的主要区别在于当可选值为空时可选链式调用只会调用失败,然而强制展开将会触发运行时错误。
通过在想调用的属性、方法,或下标的可选值后面放一个问号(`?`),可以定义一个可选链。这一点很像在可选值后面放一个叹号(`!`)来强制解包它的值。它们的主要区别在于当可选值为空时可选链式调用只会调用失败,然而强制解包将会触发运行时错误。
为了反映可选链式调用可以在空值(`nil`)上调用的事实,不论这个调用的属性、方法及下标返回的值是不是可选值,它的返回结果都是一个可选值。你可以利用这个返回值来判断你的可选链式调用是否调用成功,如果调用有返回值则说明调用成功,返回 `nil` 则说明调用失败。
这里需要特别指出,可选链式调用的返回结果与原本的返回结果具有相同的类型,但是被包装成了一个可选值。例如,使用可选链式调用访问属性,当可选链式调用成功时,如果属性原本的返回结果是 `Int` 类型,则会变为 `Int?` 类型。
下面几段代码将解释可选链式调用和强制展开的不同。
下面几段代码将解释可选链式调用和强制解包的不同。
首先定义两个类 `Person``Residence`
@ -36,7 +36,7 @@ class Residence {
let john = Person()
```
如果使用叹号(`!`)强制展开获得这个 `john``residence` 属性中的 `numberOfRooms` 值,会触发运行时错误,因为这时 `residence` 没有可以展开的值:
如果使用叹号(`!`)强制解包获得这个 `john``residence` 属性中的 `numberOfRooms` 值,会触发运行时错误,因为这时 `residence` 没有可以解包的值:
```swift
let roomCount = john.residence!.numberOfRooms
@ -58,7 +58,7 @@ if let roomCount = john.residence?.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`
@ -156,7 +156,7 @@ class Address {
## 通过可选链式调用访问属性 {#accessing-properties-through-optional-chaining}
正如 [使用可选链式调用代替强制展开](#optional_chaining_as_an_alternative_to_forced_unwrapping) 中所述,可以通过可选链式调用在一个可选值上访问它的属性,并判断访问是否成功。
正如 [使用可选链式调用代替强制解包](#optional-chaining-as-an-alternative-to-forced-unwrapping) 中所述,可以通过可选链式调用在一个可选值上访问它的属性,并判断访问是否成功。
使用前面定义过的类,创建一个 `Person` 实例,然后像之前一样,尝试访问 `numberOfRooms` 属性:
@ -212,7 +212,7 @@ func printNumberOfRooms() {
}
```
这个方法没有返回值。然而,没有返回值的方法具有隐式的返回类型 `Void`,如 [无返回值函数](./06_Functions.md#functions_without_return_values) 中所述。这意味着没有返回值的方法也会返回 `()`,或者说空的元组。
这个方法没有返回值。然而,没有返回值的方法具有隐式的返回类型 `Void`,如 [无返回值函数](./06_Functions.md#functions-without-return-values) 中所述。这意味着没有返回值的方法也会返回 `()`,或者说空的元组。
如果在可选值上通过可选链式调用来调用这个方法,该方法的返回类型会是 `Void?`,而不是 `Void`,因为通过可选链式调用得到的返回值都是可选的。这样我们就可以使用 `if` 语句来判断能否成功调用 `printNumberOfRooms()` 方法,即使方法本身没有定义返回值。通过判断返回值是否为 `nil` 可以判断调用是否成功:
@ -225,7 +225,7 @@ if john.residence?.printNumberOfRooms() != nil {
// 打印“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
if (john.residence?.address = someAddress) != nil {

View File

@ -142,12 +142,14 @@ do {
statements
} catch pattern 2 where condition {
statements
} catch pattern 3, pattern 4 where condition {
statements
} catch {
statements
}
```
`catch` 后面写一个匹配模式来表明这个子句能处理什么样的错误。如果一条 `catch` 子句没有指定匹配模式,那么这条子句可以匹配任何错误,并且把错误绑定到一个名字为 `error` 的局部常量。关于模式匹配的更多信息请参考 [模式](../chapter3/07_Patterns.html)。
`catch` 后面写一个匹配模式来表明这个子句能处理什么样的错误。如果一条 `catch` 子句没有指定匹配模式,那么这条子句可以匹配任何错误,并且把错误绑定到一个名字为 `error` 的局部常量。关于模式匹配的更多信息请参考 [模式](../03_language_reference/08_Patterns.md)。
举例来说,下面的代码处理了 `VendingMachineError` 枚举类型的全部三种情况:
@ -173,14 +175,14 @@ do {
`catch` 子句不必将 `do` 子句中的代码所抛出的每一个可能的错误都作处理。如果所有 `catch` 子句都未处理错误,错误就会传递到周围的作用域。然而,错误还是必须要被某个周围的作用域处理的。在不会抛出错误的函数中,必须用 `do-catch` 语句处理错误。而能够抛出错误的函数既可以使用 `do-catch` 语句处理,也可以让调用方来处理错误。如果错误传递到了顶层作用域却依然没有被处理,你会得到一个运行时错误。
以下面的代码为例,不是 `VendingMachineError`明的错误会在调用函数的地方被捕获:
以下面的代码为例,不是 `VendingMachineError`明的错误会在调用函数的地方被捕获:
```swift
func nourish(with item: String) throws {
do {
try vendingMachine.vend(itemNamed: item)
} catch is VendingMachineError {
print("Invalid selection, out of stock, or not enough money.")
print("Couldn't buy that from the vending machine.")
}
}
@ -189,12 +191,28 @@ do {
} catch {
print("Unexpected non-vending-machine-related error: \(error)")
}
// 打印“Invalid selection, out of stock, or not enough money.”
// 打印“Couldn't buy that from the vending machine.”
```
如果 `vend(itemNamed:)` 抛出的是一个 `VendingMachineError` 类型的错误,`nourish(with:)` 会打印一条消息,否则 `nourish(with:)` 会将错误抛给它的调用方。这个错误之后会被通用的 `catch` 语句捕获。
### 将错误转换成可选值 {#converting_errors_to_optional_values}
另一种捕获多个相关错误的方式是将它们放在 `catch` 后,通过逗号分隔。
例如:
```swift
func eat(item: String) throws {
do {
try vendingMachine.vend(itemNamed: item)
} catch VendingMachineError.invalidSelection, VendingMachineError.insufficientFunds, VendingMachineError.outOfStock {
print("Invalid selection, out of stock, or not enough money.")
}
}
```
`eat(item:)` 函数捕获了列出来的 `VendingMachine` 错误,且它的错误文本和列表的错误相关。如果列出来的三个错误中任意一个抛出,这个 `catch` 代码块就会打印信息。其他错误会传递到外面的作用域,包括以后可能添加的其他 `VendingMachine` 错误。
### 将错误转换成可选值 {#converting-errors-to-optional-values}
可以使用 `try?` 通过将错误转换成一个可选值来处理错误。如果是在计算 `try?` 表达式时抛出错误,该表达式的结果就为 `nil`。例如,在下面的代码中,`x``y` 有着相同的数值和等价的含义:
@ -225,7 +243,7 @@ func fetchData() -> Data? {
}
```
### 禁用错误传递 {#disabling_error_propagation}
### 禁用错误传递 {#disabling-error-propagation}
有时你知道某个 `throwing` 函数实际上在运行时是不会抛出错误的,在这种情况下,你可以在表达式前面写 `try!` 来禁用错误传递,这会把调用包装在一个不会有错误抛出的运行时断言中。如果真的抛出了错误,你会得到一个运行时错误。

View File

@ -4,7 +4,7 @@
类型转换在 Swift 中使用 `is``as` 操作符实现。这两个操作符分别提供了一种简单达意的方式去检查值的类型或者转换它的类型。
你也可以用它来检查一个类型是否遵循了某个协议,就像在 [检验协议遵循](./21_Protocols.md#checking_for_protocol_conformance) 部分讲述的一样。
你也可以用它来检查一个类型是否遵循了某个协议,就像在 [检验协议遵循](./21_Protocols.md#checking-for-protocol-conformance) 部分讲述的一样。
## 为类型转换定义类层次 {#defining-a-class-hierarchy-for-type-casting}

View File

@ -63,7 +63,7 @@ struct BlackjackCard {
`BlackjackCard` 结构体拥有两个属性——`rank``suit`。它也同样定义了一个计算型属性 `description``description` 属性用 `rank``suit` 中的内容来构建对扑克牌名字和数值的描述。该属性使用可选绑定来检查可选类型 `second` 是否有值,若有值,则在原有的描述中增加对 `second` 的描述。
因为 `BlackjackCard` 是一个没有自定义构造器的结构体,在 [结构体的逐一成员构造器](./14_Initialization.md#memberwise_initializers_for_structure_types) 中可知,结构体有默认的成员构造器,所以你可以用默认的构造器去初始化新常量 `theAceOfSpades`
因为 `BlackjackCard` 是一个没有自定义构造器的结构体,在 [结构体的逐一成员构造器](./14_Initialization.md#memberwise-initializers-for-structure-types) 中可知,结构体有默认的成员构造器,所以你可以用默认的构造器去初始化新常量 `theAceOfSpades`
```swift
let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)

View File

@ -87,7 +87,7 @@ print("A marathon is \(aMarathon) meters long")
扩展可以给一个类添加新的便利构造器,但是它们不能给类添加新的指定构造器或者析构器。指定构造器和析构器必须始终由类的原始实现提供。
如果你使用扩展给一个值类型添加构造器只是用于给所有存储属性提供默认值,且没有定义任何自定义构造器,那么你可以在该值类型扩展的构造器中使用默认构造器和成员构造器。如果你构造器写到了值类型的原始实现中,就像 [值类型的构造器委托](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#ID215) 中所描述的,那么就不属于在扩展中添加构造器
如果你使用扩展给一个值类型添加构造器,而这个值类型已经为所有存储属性提供默认值,且没有定义任何自定义构造器,那么你可以在该值类型扩展的构造器中使用默认构造器和成员构造器。如果你已经将构造器写值类型的原始实现中,则不适用于这种情况,如同 [值类型的构造器委托](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#ID215) 中所描述的那样
如果你使用扩展给另一个模块中定义的结构体添加构造器,那么新的构造器直到定义模块中使用一个构造器之前,不能访问 `self`

View File

@ -22,7 +22,7 @@ struct SomeStructure: FirstProtocol, AnotherProtocol {
}
```
若一个拥有父类的类在遵循协议时,应该将父类名放在协议名之前,以逗号分隔:
一个拥有父类,应该将父类名放在遵循的协议名之前,以逗号分隔:
```swift
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
@ -75,7 +75,7 @@ let john = Person(fullName: "John Appleseed")
这个例子中定义了一个叫做 `Person` 的结构体,用来表示一个具有名字的人。从第一行代码可以看出,它遵循了 `FullyNamed` 协议。
`Person` 结构体的每一个实例都有一个 `String` 类型的存储型属性 `fullName`。这正好满足了 `FullyNamed` 协议的要求,也就意味着 `Person` 结构体正确地符合了协议。(如果协议要求未被完全满足,在编译时会报错。)
`Person` 结构体的每一个实例都有一个 `String` 类型的存储型属性 `fullName`。这正好满足了 `FullyNamed` 协议的要求,也就意味着 `Person` 结构体正确地遵循了协议。(如果协议要求未被完全满足,在编译时会报错。)
下面是一个更为复杂的类,它采纳并遵循了 `FullyNamed` 协议:
@ -143,7 +143,7 @@ print("And another one: \(generator.random())")
## 异变方法要求 {#mutating-method-requirements}
有时需要在方法中改变(或*异变*)方法所属的实例。例如,在值类型(即结构体和枚举)的实例方法中,将 `mutating` 关键字作为方法的前缀,写在 `func` 关键字之前,表示可以在该方法中修改它所属的实例以及实例的任意属性的值。这一过程在 [在实例方法中修改值类型](./11_Methods.md#modifying_value_types_from_within_instance_methods) 章节中有详细描述。
有时需要在方法中改变(或*异变*)方法所属的实例。例如,在值类型(即结构体和枚举)的实例方法中,将 `mutating` 关键字作为方法的前缀,写在 `func` 关键字之前,表示可以在该方法中修改它所属的实例以及实例的任意属性的值。这一过程在 [在实例方法中修改值类型](./11_Methods.md#modifying-value-types-from-within-instance-methods) 章节中有详细描述。
如果你在协议中定义了一个实例方法,该方法会改变遵循该协议的类型的实例,那么在定义协议时需要在方法前加 `mutating` 关键字。这使得结构体和枚举能够遵循此协议并满足此方法要求。
@ -204,13 +204,13 @@ class SomeClass: SomeProtocol {
}
```
使用 `required` 修饰符可以确保所有子类也必须提供此构造器实现,从而也能符合协议。
使用 `required` 修饰符可以确保所有子类也必须提供此构造器实现,从而也能遵循协议。
关于 `required` 构造器的更多内容,请参考 [必要构造器](./14_Initialization.md#required_initializers)。
关于 `required` 构造器的更多内容,请参考 [必要构造器](./14_Initialization.md#required-initializers)。
> 注意
>
> 如果类已经被标记为 `final`,那么不需要在协议构造器的实现中使用 `required` 修饰符,因为 `final` 类不能有子类。关于 `final` 修饰符的更多内容,请参见 [防止重写](./13_Inheritance.md#preventing_overrides)。
> 如果类已经被标记为 `final`,那么不需要在协议构造器的实现中使用 `required` 修饰符,因为 `final` 类不能有子类。关于 `final` 修饰符的更多内容,请参见 [防止重写](./13_Inheritance.md#preventing-overrides)。
如果一个子类重写了父类的指定构造器,并且该构造器满足了某个协议的要求,那么该构造器的实现需要同时标注 `required``override` 修饰符:
@ -236,7 +236,7 @@ class SomeSubClass: SomeSuperClass, SomeProtocol {
### 可失败构造器要求 {#failable-initializer-requirements}
协议还可以为遵循协议的类型定义可失败构造器要求,详见 [可失败构造器](./14_Initialization.md#failable_initializers)。
协议还可以为遵循协议的类型定义可失败构造器要求,详见 [可失败构造器](./14_Initialization.md#failable-initializers)。
遵循协议的类型可以通过可失败构造器(`init?`)或非可失败构造器(`init`)来满足协议中定义的可失败构造器要求。协议中定义的非可失败构造器要求可以通过非可失败构造器(`init`)或隐式解包可失败构造器(`init!`)来满足。
@ -272,7 +272,7 @@ class Dice {
例子中定义了一个 `Dice` 类,用来代表桌游中拥有 N 个面的骰子。`Dice` 的实例含有 `sides``generator` 两个属性,前者是整型,用来表示骰子有几个面,后者为骰子提供一个随机数生成器,从而生成随机点数。
`generator` 属性的类型为 `RandomNumberGenerator`,因此任何遵循了 `RandomNumberGenerator` 协议的类型的实例都可以赋值给 `generator`,除此之外并无其他要求。并且由于其类型是 `RandomNumberGenerator`,在 `Dice` 类中与 `generator` 交互的代码,必须适用于所有 `generator` 实例都遵循的方法。这句话的意思是不能使用由 `generator` 底层类型提供的任何方法或属性。但是你可以通过向下转型,从协议类型转换成底层实现类型,比如从父类向下转型为子类。请参考 [向下转型](./18_Type_Casting#downcasting)。
`generator` 属性的类型为 `RandomNumberGenerator`,因此任何遵循了 `RandomNumberGenerator` 协议的类型的实例都可以赋值给 `generator`,除此之外并无其他要求。并且由于其类型是 `RandomNumberGenerator`,在 `Dice` 类中与 `generator` 交互的代码,必须适用于所有 `generator` 实例都遵循的方法。这句话的意思是不能使用由 `generator` 底层类型提供的任何方法或属性。但是你可以通过向下转型,从协议类型转换成底层实现类型,比如从父类向下转型为子类。请参考 [向下转型](./18_Type_Casting.md#downcasting)。
`Dice` 类还有一个构造器,用来设置初始状态。构造器有一个名为 `generator`,类型为 `RandomNumberGenerator` 的形参。在调用构造方法创建 `Dice` 的实例时,可以传入任何遵循 `RandomNumberGenerator` 协议的实例给 `generator`
@ -312,7 +312,7 @@ protocol DiceGameDelegate {
`DiceGame` 协议可以被任意涉及骰子的游戏遵循。
`DiceGameDelegate` 协议可以被任意类型遵循,用来追踪 `DiceGame` 的游戏过程。为了防止强引用导致的循环引用问题,可以把协议声明为弱引用,更多相关的知识请看 [类实例之间的循环强引用](./23_Automatic_Reference_Counting.md#strong_reference_cycles_between_class_instances),当协议标记为类专属可以使 `SnakesAndLadders` 类在声明协议时强制要使用弱引用。若要声明类专属的协议就必须继承于 `AnyObject` ,更多请看 [类专属的协议](#class_only_protocol)。
`DiceGameDelegate` 协议可以被任意类型遵循,用来追踪 `DiceGame` 的游戏过程。为了防止强引用导致的循环引用问题,可以把协议声明为弱引用,更多相关的知识请看 [类实例之间的循环强引用](./24_Automatic_Reference_Counting.md#strong-reference-cycles-between-class-instances),当协议标记为类专属可以使 `SnakesAndLadders` 类在声明协议时强制要使用弱引用。若要声明类专属的协议就必须继承于 `AnyObject` ,更多请看 [类专属的协议](#class-only-protocol)。
如下所示,`SnakesAndLadders` 是 [控制流](./05_Control_Flow.md) 章节引入的蛇梯棋游戏的新版本。新版本使用 `Dice` 实例作为骰子,并且实现了 `DiceGame``DiceGameDelegate` 协议,后者用来记录游戏的过程:
@ -355,7 +355,7 @@ class SnakesAndLadders: DiceGame {
游戏使用 `SnakesAndLadders` 类的 `init()` 构造器来初始化游戏。所有的游戏逻辑被转移到了协议中的 `play()` 方法,`play()` 方法使用协议要求的 `dice` 属性提供骰子摇出的值。
注意,`delegate` 并不是游戏的必备条件,因此 `delegate` 被定义为 `DiceGameDelegate` 类型的可选属性。因为 `delegate` 是可选值,因此会被自动赋予初始值 `nil`。随后,可以在游戏中为 `delegate` 设置适当的值。
注意,`delegate` 并不是游戏的必备条件,因此 `delegate` 被定义为 `DiceGameDelegate` 类型的可选属性。因为 `delegate` 是可选值,因此会被自动赋予初始值 `nil`。随后,可以在游戏中为 `delegate` 设置适当的值。因为 `DiceGameDelegate` 协议是类专属的,可以将 `delegate` 声明为 `weak`,从而避免循环引用。
`DicegameDelegate` 协议提供了三个方法用来追踪游戏过程。这三个方法被放置于游戏的逻辑中,即 `play()` 方法内。分别在游戏开始时,新一轮开始时,以及游戏结束时被调用。
@ -387,7 +387,7 @@ class DiceGameTracker: DiceGameDelegate {
`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` 属性的值。
`DiceGameTracker` 的运行情况如下所示:
@ -455,7 +455,7 @@ print(game.textualDescription)
## 有条件地遵循协议 {#Conditionally-Conforming-to-a-Protocol}
泛型类型可能只在某些情况下满足一个协议的要求,比如当类型的泛型形式参数遵循对应协议时。你可以通过在扩展类型时列出限制让泛型类型有条件地遵循某协议。在你采纳协议的名字后面写泛型 `where` 分句。更多关于泛型 `where` 分句,见 [泛型 Where 分句](./22_Generics.md##where_clauses)。
泛型类型可能只在某些情况下满足一个协议的要求,比如当类型的泛型形式参数遵循对应协议时。你可以通过在扩展类型时列出限制让泛型类型有条件地遵循某协议。在你采纳协议的名字后面写泛型 `where` 分句。更多关于泛型 `where` 分句,见 [泛型 Where 分句](./22_Generics.md##where-clauses)。
下面的扩展让 `Array` 类型只要在存储遵循 `TextRepresentable` 协议的元素时就遵循 `TextRepresentable` 协议。
@ -473,7 +473,7 @@ print(myDice.textualDescription)
## 在扩展里声明采纳协议 {#declaring-protocol-adoption-with-an-extension}
当一个类型已经符合了某个协议中的所有要求,却还没有声明采纳该协议时,可以通过空的扩展来让它采纳该协议:
当一个类型已经遵循了某个协议中的所有要求,却还没有声明采纳该协议时,可以通过空的扩展来让它采纳该协议:
```swift
struct Hamster {
@ -498,9 +498,65 @@ print(somethingTextRepresentable.textualDescription)
>
> 即使满足了协议的所有要求,类型也不会自动遵循协议,必须显式地遵循协议。
## 使用合成实现来采纳协议 {#adopting-a-protocol-using-a-synthesized-implementation}
Swift 可以自动提供一些简单场景下遵循 `Equatable``Hashable``Comparable` 协议的实现。在使用这些合成实现之后,无需再编写重复的代码来实现这些协议所要求的方法。
Swift 为以下几种自定义类型提供了 `Equatable` 协议的合成实现:
- 遵循 `Equatable` 协议且只有存储属性的结构体。
- 遵循 `Equatable` 协议且只有关联类型的枚举
- 没有任何关联类型的枚举
在包含类型原始声明的文件中声明对 `Equatable` 协议的遵循,可以得到 `==` 操作符的合成实现,且无需自己编写任何关于 `==` 的实现代码。`Equatable` 协议同时包含 `!=` 操作符的默认实现。
下面的例子中定义了一个 `Vector3D` 结构体来表示一个类似 `Vector2D` 的三维向量 `(x, y, z)`。由于 `x``y``z` 都是满足 `Equatable` 的类型,`Vector3D` 可以得到连等判断的合成实现。
```swift
struct Vector3D: Equatable {
var x = 0.0, y = 0.0, z = 0.0
}
let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
print("These two vectors are also equivalent.")
}
// 打印 "These two vectors are also equivalent."
```
Swift 为以下几种自定义类型提供了 `Hashable` 协议的合成实现:
- 遵循 `Hashable` 协议且只有存储属性的结构体。
- 遵循 `Hashable` 协议且只有关联类型的枚举
- 没有任何关联类型的枚举
在包含类型原始声明的文件中声明对 `Hashable` 协议的遵循,可以得到 `hash(into:)` 的合成实现,且无需自己编写任何关于 `hash(into:)` 的实现代码。
Swift 为没有原始值的枚举类型提供了 `Comparable` 协议的合成实现。如果枚举类型包含关联类型,那这些关联类型也必须同时遵循 `Comparable` 协议。在包含原始枚举类型声明的文件中声明其对 `Comparable` 协议的遵循,可以得到 `<` 操作符的合成实现,且无需自己编写任何关于 `<` 的实现代码。`Comparable` 协议同时包含 `<=``>``>=` 操作符的默认实现。
下面的例子中定义了 `SkillLevel` 枚举类型其中定义了初学者beginner、中级intermediate和专家expert三种等级专家等级会由额外的星级stars来进行排名。
```swift
enum SkillLevel: Comparable {
case beginner
case intermediate
case expert(stars: Int)
}
var levels = [SkillLevel.intermediate, SkillLevel.beginner,
SkillLevel.expert(stars: 5), SkillLevel.expert(stars: 3)]
for level in levels.sorted() {
print(level)
}
// 打印 "beginner"
// 打印 "intermediate"
// 打印 "expert(stars: 3)"
// 打印 "expert(stars: 5)"
```
## 协议类型的集合 {#collections-of-protocol-types}
协议类型可以在数组或者字典这样的集合中使用,在 [协议类型](./21_Protocols.md##protocols_as_types) 提到了这样的用法。下面的例子创建了一个元素类型为 `TextRepresentable` 的数组:
协议类型可以在数组或者字典这样的集合中使用,在 [协议类型](./21_Protocols.md##protocols-as-types) 提到了这样的用法。下面的例子创建了一个元素类型为 `TextRepresentable` 的数组:
```swift
let things: [TextRepresentable] = [game, d12, simonTheHamster]
@ -588,7 +644,7 @@ protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
> 注意
>
> 当协议定义的要求需要遵循协议的类型必须是引用语义而非值语义时,应该采用类类型专属协议。关于引用语义和值语义的更多内容,请查看 [结构体和枚举是值类型](./09_Classes_and_Structures.md#structures_and_enumerations_are_value_types) 和 [类是引用类型](./09_Classes_and_Structures.md#classes_are_reference_types)。
> 当协议定义的要求需要遵循协议的类型必须是引用语义而非值语义时,应该采用类类型专属协议。关于引用语义和值语义的更多内容,请查看 [结构体和枚举是值类型](./09_Structures_And_Classes.md#structures-and-enumerations-are-value-types) 和 [类是引用类型](./09_Structures_And_Classes.md#classes-are-reference-types)。
## 协议合成 {#protocol-composition}
@ -619,9 +675,9 @@ wishHappyBirthday(to: birthdayPerson)
`Named` 协议包含 `String` 类型的 `name` 属性。`Aged` 协议包含 `Int` 类型的 `age` 属性。`Person` 结构体采纳了这两个协议。
`wishHappyBirthday(to:)` 函数的参数 `celebrator` 的类型为 `Named & Aged` 这意味着“任何同时遵循 Named 和 Aged 的协议”。它不关心参数的具体类型,只要参数符合这两个协议即可。
`wishHappyBirthday(to:)` 函数的参数 `celebrator` 的类型为 `Named & Aged` 这意味着“任何同时遵循 Named 和 Aged 的协议”。它不关心参数的具体类型,只要参数遵循这两个协议即可。
上面的例子创建了一个名为 `birthdayPerson``Person` 的实例,作为参数传递给了 `wishHappyBirthday(to:)` 函数。因为 `Person` 同时符合这两个协议,所以这个参数合法,函数将打印生日问候语。
上面的例子创建了一个名为 `birthdayPerson``Person` 的实例,作为参数传递给了 `wishHappyBirthday(to:)` 函数。因为 `Person` 同时遵循这两个协议,所以这个参数合法,函数将打印生日问候语。
这里有一个例子:将 Location 类和前面的 Named 协议进行组合:
@ -650,16 +706,16 @@ beginConcert(in: seattle)
// 打印 "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:)` 函数也是非法的。
## 检查协议一致性 {#checking-for-protocol-conformance}
你可以使用 [类型转换](./18_Type_Casting.md) 中描述的 `is``as` 操作符来检查协议一致性,即是否符合某协议,并且可以转换到指定的协议类型。检查和转换协议的语法与检查和转换类型是完全一样的:
你可以使用 [类型转换](./18_Type_Casting.md) 中描述的 `is``as` 操作符来检查协议一致性,即是否遵循某协议,并且可以转换到指定的协议类型。检查和转换协议的语法与检查和转换类型是完全一样的:
* `is` 用来检查实例是否符合某个协议,若符合则返回 `true`,否则返回 `false`
* `as?` 返回一个可选值,当实例符合某个协议时,返回类型为协议类型的可选值,否则返回 `nil`
* `is` 用来检查实例是否遵循某个协议,若遵循则返回 `true`,否则返回 `false`
* `as?` 返回一个可选值,当实例遵循某个协议时,返回类型为协议类型的可选值,否则返回 `nil`
* `as!` 将实例强制向下转换到某个协议类型,如果强转失败,将触发运行时错误。
下面的例子定义了一个 `HasArea` 协议,该协议定义了一个 `Double` 类型的可读属性 `area`
@ -708,7 +764,7 @@ let objects: [AnyObject] = [
`objects` 数组使用字面量初始化,数组包含一个 `radius``2``Circle` 的实例,一个保存了英国国土面积的 `Country` 实例和一个 `legs``4``Animal` 实例。
如下所示,`objects` 数组可以被迭代,并对迭代出的每一个元素进行检查,看它是否符合 `HasArea` 协议:
如下所示,`objects` 数组可以被迭代,并对迭代出的每一个元素进行检查,看它是否遵循 `HasArea` 协议:
```swift
for object in objects {
@ -723,7 +779,7 @@ for object in objects {
// Something that doesn't have an area
```
当迭代出的元素符合 `HasArea` 协议时,将 `as?` 操作符返回的可选值通过可选绑定,绑定到 `objectWithArea` 常量上。`objectWithArea``HasArea` 协议类型的实例,因此 `area` 属性可以被访问和打印。
当迭代出的元素遵循 `HasArea` 协议时,将 `as?` 操作符返回的可选值通过可选绑定,绑定到 `objectWithArea` 常量上。`objectWithArea``HasArea` 协议类型的实例,因此 `area` 属性可以被访问和打印。
`objects` 数组中的元素的类型并不会因为强转而丢失类型信息,它们仍然是 `Circle``Country``Animal` 类型。然而,当它们被赋值给 `objectWithArea` 常量时,只被视为 `HasArea` 类型,因此只有 `area` 属性能够被访问。
@ -772,7 +828,7 @@ class Counter {
这里使用了两层可选链式调用。首先,由于 `dataSource` 可能为 `nil`,因此在 `dataSource` 后边加上了 `?`,以此表明只在 `dataSource` 非空时才去调用 `increment(forCount:)` 方法。其次,即使 `dataSource` 存在,也无法保证其是否实现了 `increment(forCount:)` 方法,因为这个方法是可选的。因此,`increment(forCount:)` 方法同样使用可选链式调用进行调用,只有在该方法被实现的情况下才能调用它,所以在 `increment(forCount:)` 方法后边也加上了 `?`
调用 `increment(forCount:)` 方法在上述两种情形下都有可能失败,所以返回值为 `Int?` 类型。虽然在 `CounterDataSource` 协议中,`increment(forCount:)` 的返回值类型是非可选 `Int`。另外,即使这里使用了两层可选链式调用,最后的返回结果依旧是单层的可选类型。关于这一点的更多信息,请查阅 [连接多层可选链式调用](./16_Optional_Chaining)。
调用 `increment(forCount:)` 方法在上述两种情形下都有可能失败,所以返回值为 `Int?` 类型。虽然在 `CounterDataSource` 协议中,`increment(forCount:)` 的返回值类型是非可选 `Int`。另外,即使这里使用了两层可选链式调用,最后的返回结果依旧是单层的可选类型。关于这一点的更多信息,请查阅 [连接多层可选链式调用](./16_Optional_Chaining.md)。
在调用 `increment(forCount:)` 方法后,`Int?` 型的返回值通过可选绑定解包并赋值给常量 `amount`。如果可选值确实包含一个数值,也就是说,数据源和方法都存在,数据源方法返回了一个有效值。之后便将解包后的 `amount` 加到 `count` 上,增量操作完成。
@ -861,9 +917,11 @@ print("And here's a random Boolean: \(generator.randomBool())")
// 打印 “And here's a random Boolean: true”
```
协议扩展可以为遵循协议的类型增加实现,但不能声明该协议继承自另一个协议。协议的继承只能在协议声明处进行指定。
### 提供默认实现 {#providing-default-implementations}
可以通过协议扩展来为协议要求的属性、方法以及下标提供默认的实现。如果遵循协议的类型为这些要求提供了自己的实现,那么这些自定义实现将会替代扩展中的默认实现被使用。
可以通过协议扩展来为协议要求的方法、计算属性提供默认的实现。如果遵循协议的类型为这些要求提供了自己的实现,那么这些自定义实现将会替代扩展中的默认实现被使用。
> 注意
>
@ -881,9 +939,9 @@ extension PrettyTextRepresentable {
### 为协议扩展添加限制条件 {#adding-constraints-to-protocol-extensions}
在扩展协议的时候,可以指定一些限制条件,只有遵循协议的类型满足这些限制条件时,才能获得协议扩展提供的默认实现。这些限制条件写在协议名之后,使用 `where` 子句来描述,正如 [泛型 Where 子句](./22_Generics.md#where_clauses) 中所描述的。
在扩展协议的时候,可以指定一些限制条件,只有遵循协议的类型满足这些限制条件时,才能获得协议扩展提供的默认实现。这些限制条件写在协议名之后,使用 `where` 子句来描述,正如 [泛型 Where 子句](./22_Generics.md#where-clauses) 中所描述的。
例如,你可以扩展 `Collection` 协议,适用于集合中的元素遵循了 `Equatable` 协议的情况。通过限制集合元素遵 `Equatable` 协议, 作为标准库的一部分, 你可以使用 `==``!=` 操作符来检查两个元素的等价性和非等价性。
例如,你可以扩展 `Collection` 协议,适用于集合中的元素遵循了 `Equatable` 协议的情况。通过限制集合元素遵 `Equatable` 协议, 作为标准库的一部分, 你可以使用 `==``!=` 操作符来检查两个元素的等价性和非等价性。
```swift
extension Collection where Element: Equatable {

View File

@ -16,7 +16,7 @@ func swapTwoInts(_ a: inout Int, _ b: inout Int) {
}
```
这个函数使用输入输出参数(`inout`)来交换 `a``b` 的值,具体请参考 [输入输出参数](./06_Functions.md#in_out_parameters)。
这个函数使用输入输出参数(`inout`)来交换 `a``b` 的值,具体请参考 [输入输出参数](./06_Functions.md#in-out-parameters)。
`swapTwoInts(_:_:)` 函数将 `b` 的原始值换成了 `a`,将 `a` 的原始值换成了 `b`,你可以调用这个函数来交换两个 `Int` 类型变量:
@ -44,7 +44,7 @@ func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
}
```
你可能注意到了,`swapTwoInts(_:_:)``swapTwoStrings(_:_:)``swapTwoDoubles(_:_:)` 函数体是一样的,唯一的区别是它们接受的参数类型(`Int``String``Double`)。
你可能注意到了,`swapTwoInts(_:_:)``swapTwoStrings(_:_:)``swapTwoDoubles(_:_:)` 函数体是一样的,唯一的区别是它们接受的参数类型(`Int``String``Double`)。
在实际应用中,通常需要一个更实用更灵活的函数来交换两个任意类型的值,幸运的是,泛型代码帮你解决了这种问题。(这些函数的泛型版本已经在下面定义好了。)
@ -226,7 +226,7 @@ if let topItem = stackOfStrings.topItem {
// 打印“The top item on the stack is tres.”
```
泛型类型的扩展,还可以包括类型扩展需要额外满足的条件,从而对类型添加新功能,这一部分将在[具有泛型 Where 子句的扩展](#extensions-with-a-generic-where-clause)中进行讨论。
泛型类型的扩展,还可以包括类型扩展需要额外满足的条件,从而对类型添加新功能,这一部分将在 [具有泛型 Where 子句的扩展](#extensions-with-a-generic-where-clause) 中进行讨论。
## 类型约束 {#type-constraints}
@ -234,7 +234,7 @@ if let topItem = stackOfStrings.topItem {
例如Swift 的 `Dictionary` 类型对字典的键的类型做了些限制。在 [字典的描述](./04_Collection_Types.md#dictionaries) 中字典键的类型必须是可哈希hashable的。也就是说必须有一种方法能够唯一地表示它。字典键之所以要是可哈希的是为了便于检查字典中是否已经包含某个特定键的值。若没有这个要求字典将无法判断是否可以插入或替换某个指定键的值也不能查找到已经存储在字典中的指定键的值。
这个要求通过 `Dictionary` 键类型上的类型约束实现,它指明了键必须遵循 Swift 标准库中定义的 `Hashable` 协议。所有 Swift 的基本类型(例如 `String``Int``Double``Bool`)默认都是可哈希的。
这个要求通过 `Dictionary` 键类型上的类型约束实现,它指明了键必须遵循 Swift 标准库中定义的 `Hashable` 协议。所有 Swift 的基本类型(例如 `String``Int``Double``Bool`)默认都是可哈希的。如何让自定义类型遵循 `Hashable` 协议,可以查看文档 [遵循 Hashable 协议](https://developer.apple.com/documentation/swift/hashable#2849490)。
当自定义泛型类型时,你可以定义你自己的类型约束,这些约束将提供更为强大的泛型编程能力。像 `可哈希hashable` 这种抽象概念根据它们的概念特征来描述类型,而不是它们的具体类型。
@ -410,7 +410,7 @@ struct Stack<Element>: Container {
### 扩展现有类型来指定关联类型 {#extending-an-existing-type-to-specify-an-associated-type}
[在扩展添加协议一致性](./21_Protocols.md#adding_protocol_conformance_with_an_extension) 中描述了如何利用扩展让一个已存在的类型遵循一个协议,这包括使用了关联类型协议。
[在扩展添加协议一致性](./21_Protocols.md#adding-protocol-conformance-with-an-extension) 中描述了如何利用扩展让一个已存在的类型遵循一个协议,这包括使用了关联类型协议。
Swift 的 `Array` 类型已经提供 `append(_:)` 方法,`count` 属性,以及带有 `Int` 索引的下标来检索其元素。这三个功能都符合 `Container` 协议的要求,也就意味着你只需声明 `Array` 遵循`Container` 协议,就可以扩展 Array使其遵从 Container 协议。你可以通过一个空扩展来实现这点,正如通过扩展采纳协议中的描述:
@ -446,7 +446,7 @@ protocol SuffixableContainer: Container {
}
```
在这个协议里,`Suffix` 是一个关联类型,就像上边例子中 `Container``Item` 类型一样。`Suffix` 拥有两个约束:它必须遵循 `SuffixableContainer` 协议(就是当前定义的协议),以及它的 `Item` 类型必须是和容器里的 `Item` 类型相同。`Item` 的约束是一个 `where` 分句,它在下面[具有泛型 Where 子句的扩展](#extensions-with-a-generic-where-clause)中有讨论。
在这个协议里,`Suffix` 是一个关联类型,就像上边例子中 `Container``Item` 类型一样。`Suffix` 拥有两个约束:它必须遵循 `SuffixableContainer` 协议(就是当前定义的协议),以及它的 `Item` 类型必须是和容器里的 `Item` 类型相同。`Item` 的约束是一个 `where` 分句,它在下面 [具有泛型 Where 子句的扩展](#extensions-with-a-generic-where-clause) 中有讨论。
这是上面 [泛型类型](#generic-types) 中 `Stack` 类型的扩展,它遵循了 SuffixableContainer 协议:
@ -486,7 +486,7 @@ extension IntStack: SuffixableContainer {
## 泛型 Where 语句 {#where-clauses}
[类型约束](#type_constraints) 让你能够为泛型函数、下标、类型的类型参数定义一些强制要求。
[类型约束](#type-constraints) 让你能够为泛型函数、下标、类型的类型参数定义一些强制要求。
对关联类型添加约束通常是非常有用的。你可以通过定义一个泛型 `where` 子句来实现。通过泛型 `where` 子句让关联类型遵从某个特定的协议,以及某个特定的类型参数和关联类型必须类型相同。你可以通过将 `where` 关键字紧跟在类型参数列表后面来定义 `where` 子句,`where` 子句后跟一个或者多个针对关联类型的约束,以及一个或多个类型参数和关联类型间的相等关系。你可以在函数体或者类型的大括号之前添加 `where` 子句。
@ -643,9 +643,55 @@ print([1260.0, 1200.0, 98.6, 37.0].average())
就像可以在其他地方写泛型 `where` 子句一样,你可以在一个泛型 `where` 子句中包含多个条件作为扩展的一部分。用逗号分隔列表中的每个条件。
## 包含上下文关系的 where 分句 {#contextual-where-clauses}
当你使用泛型时,可以为没有独立类型约束的声明添加 `where` 分句。例如,你可以使用 `where` 分句为泛型添加下标,或为扩展方法添加泛型约束。`Container` 结构体是个泛型,下面的例子通过 `where` 分句让新的方法声明其调用所需要满足的类型约束。
```swift
extension Container {
func average() -> Double where Item == Int {
var sum = 0.0
for index in 0..<count {
sum += Double(self[index])
}
return sum / Double(count)
}
func endsWith(_ item: Item) -> Bool where Item: Equatable {
return count >= 1 && self[count-1] == item
}
}
let numbers = [1260, 1200, 98, 37]
print(numbers.average())
// 输出 "648.75"
print(numbers.endsWith(37))
// 输出 "true"
```
例子中,当 `Item` 是整型时为 `Container` 添加 `average()` 方法,当 `Item` 遵循 `Equatable` 时添加 `endsWith(_:)` 方法。两个方法都通过 `where` 分句对 `Container` 中定义的泛型 `Item` 进行了约束。
如果不使用包含上下文关系的 `where` 分句,需要写两个扩展,并为每个扩展分别加上 `where` 分句。下面的例子和上面的具有相同效果。
```swift
extension Container where Item == Int {
func average() -> Double {
var sum = 0.0
for index in 0..<count {
sum += Double(self[index])
}
return sum / Double(count)
}
}
extension Container where Item: Equatable {
func endsWith(_ item: Item) -> Bool {
return count >= 1 && self[count-1] == item
}
}
```
在包含上下文关系的 `where` 分句的例子中,由于每个方法的 `where` 分句各自声明了需要满足的条件,因此 `average()``endsWith(_:)` 的实现能放在同一个扩展里。而将 `where` 分句放在扩展进行声明也能起到同样的效果,但每一个扩展只能有一个必备条件。
## 具有泛型 Where 子句的关联类型 {#associated-types-with-a-generic-where-clause}
你可以在关联类型后面加上具有泛型 `where`句。例如,建立一个包含迭代器(`Iterator`)的容器,就像是标准库中使用的 `Sequence` 协议那样。你应该这么写:
你可以在关联类型后面加上具有泛型 `where`句。例如,建立一个包含迭代器(`Iterator`)的容器,就像是标准库中使用的 `Sequence` 协议那样。你应该这么写:
```swift
protocol Container {

View File

@ -133,7 +133,7 @@ print(opaqueJoinedTriangles.draw())
// *
```
这个例子中 `opaqueJoinedTriangles` 的值和前文 [不透明类型解决的问题](#the-problem-that-opaque-types-solve) 中关于泛型的那个例子中的 `joinedTriangles` 完全一样。不过和前文不一样的是,`flip(_:)``join(_:_:)` 将对泛型参数的操作后的返回结果包装成了不透明类型,这样保证了在结果中泛型参数类型不可见。两个函数都是泛型函数,因为他们都依赖于泛型参数,而泛型参数又将 `FlippedShape``JoinedShape` 所需要的类型信息传递给它们。
这个例子中 `opaqueJoinedTriangles` 的值和前文 [不透明类型解决的问题](#the-problem-that-opaque-types-solve) 中关于泛型的那个例子中的 `joinedTriangles` 完全一样。不过和前文不一样的是,`flip(-:)``join(-:-:)` 将对泛型参数的操作后的返回结果包装成了不透明类型,这样保证了在结果中泛型参数类型不可见。两个函数都是泛型函数,因为他们都依赖于泛型参数,而泛型参数又将 `FlippedShape``JoinedShape` 所需要的类型信息传递给它们。
如果函数中有多个地方返回了不透明类型,那么所有可能的返回值都必须是同一类型。即使对于泛型函数,不透明返回类型可以使用泛型参数,但仍需保证返回类型唯一。比如,下面就是一个*非法*示例 —— 包含针对 `Square` 类型进行特殊处理的翻转函数。

View File

@ -2,7 +2,7 @@
Swift 使用*自动引用计数ARC*机制来跟踪和管理你的应用程序的内存。通常情况下Swift 内存管理机制会一直起作用你无须自己来考虑内存的管理。ARC 会在类的实例不再被使用时,自动释放其占用的内存。
然而在少数情况下为了能帮助你管理内存ARC 需要更多的,代码之间关系的信息。本章描述了这些情况,并且为你示范怎样才能使 ARC 来管理你的应用程序的所有内存。在 Swift 使用 ARC 与在 Obejctive-C 中使用 ARC 非常类似,具体请参考 [过渡到 ARC 的发布说明](https://developer.apple.com/library/content/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226)。
然而在少数情况下为了能帮助你管理内存ARC 需要更多的,代码之间关系的信息。本章描述了这些情况,并且为你示范怎样才能使 ARC 来管理你的应用程序的所有内存。在 Swift 使用 ARC 与在 Obejctive-C 中使用 ARC 非常类似,具体请参考 [过渡到 ARC 的发布说明](https://developer.apple.com/library/content/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple-ref/doc/uid/TP40011226)。
> 注意
>
@ -10,11 +10,11 @@ Swift 使用*自动引用计数ARC*机制来跟踪和管理你的应用程
## 自动引用计数的工作机制 {#how-arc-works}
当你每次创建一个类的新的实例的时候ARC 会分配一块内存来储存该实例信息。内存中会包含实例的类型信息,以及这个实例所有相关的存储属性的值。
当你创建一个新的实例ARC 会分配一块内存来储存该实例信息。内存中会包含实例的类型信息,以及这个实例所关联的任何存储属性的值。
此外当实例不再被使用时ARC 释放实例所占用的内存,并让释放的内存能挪作他用。这确保了不再被使用的实例,不会一直占用内存空间。
然而,当 ARC 收回和释放了正在被使用中的实例,该实例的属性和方法将不能再被访问和调用。实际上,如果你试图访问这个实例,你的应用程序很可能会崩溃。
然而,当 ARC 回收并释放了正在被使用中的实例,该实例的属性和方法将不能再被访问和调用。实际上,如果你试图访问这个实例,你的应用程序很可能会崩溃。
为了确保使用中的实例不会被销毁ARC 会跟踪和计算每一个实例正在被多少属性,常量和变量所引用。哪怕实例的引用数为 1ARC 都不会销毁这个实例。
@ -37,9 +37,9 @@ class Person {
}
```
`Person` 类有一个构造器,此构造器实例的 `name` 属性赋值,并打印一条消息以表明初始化过程生效。`Person` 类也拥有一个析构器,这个析构器会在实例被销毁时打印一条消息。
`Person` 类有一个构造器,此构造器实例的 `name` 属性赋值,并打印一条消息以表明初始化过程生效。`Person` 类也拥有一个析构器,这个析构器会在实例被销毁时打印一条消息。
接下来的代码片段定义了三个类型为 `Person?` 的变量,用来按照代码片段中的顺序,为新的 `Person` 实例建立多个引用。由于这些变量是被定义为可选类型(`Person?`,而不是 `Person`),它们的值会被自动初始化为 `nil`,目前还不会引用到 `Person` 类的实例。
接下来的代码片段定义了三个类型为 `Person?` 的变量,按照代码片段中的顺序,为新的 `Person` 实例建立多个引用。由于这些变量是被定义为可选类型(`Person?`,而不是 `Person`),它们的值会被自动初始化为 `nil`,目前还不会引用到 `Person` 类的实例。
```swift
var reference1: Person?
@ -87,7 +87,7 @@ reference3 = nil
然而,我们可能会写出一个类实例的强引用数*永远不能*变成 `0` 的代码。如果两个类实例互相持有对方的强引用,因而每个实例都让对方一直存在,就是这种情况。这就是所谓的*循环强引用*。
你可以通过定义类之间的关系为弱引用或无主引用,替代强引用,从而解决循环强引用的问题。具体的过程在 [解决类实例之间的循环强引用](#resolving_strong_reference_cycles_between_class_instances) 中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是怎样产生的。
你可以通过定义类之间的关系为弱引用或无主引用,替代强引用,从而解决循环强引用的问题。具体的过程在 [解决类实例之间的循环强引用](#resolving-strong-reference-cycles-between-class-instances) 中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是怎样产生的。
下面展示了一个不经意产生循环强引用的例子。例子定义了两个类:`Person``Apartment`,用来建模公寓和它其中的居民:
@ -111,9 +111,9 @@ class Apartment {
类似的,每个 `Apartment` 实例有一个叫 `unit`,类型为 `String` 的属性,并有一个可选的初始化为 `nil``tenant` 属性。`tenant` 属性是可选的,因为一栋公寓并不总是有居民。
这两个类都定义了析构器,用以在类实例被析构的时候输出信息。这让你能够知晓 `Person``Apartment` 的实例是否像预期的那样被销毁。
这两个类都定义了析构器,在类实例被析构的时候输出信息。这让你能够知晓 `Person``Apartment` 的实例是否像预期的那样被销毁。
接下来的代码片段定义了两个可选类型的变量 `john``unit4A`,并分别被设为下面的 `Apartment``Person` 的实例。这两个变量都被初始化为 `nil`,这正是可选类型的优点:
接下来的代码片段定义了两个可选类型的变量 `john``unit4A`,并分别被设为下面的 `Apartment``Person` 的实例。这两个变量都被初始化为 `nil`,这正是可选类型的优点:
```swift
var john: Person?
@ -131,7 +131,7 @@ unit4A = Apartment(unit: "4A")
![](https://docs.swift.org/swift-book/_images/referenceCycle01_2x.png)
现在你能够将这两个实例关联在一起,这样人就能有公寓住了,而公寓也有了房客。注意感叹号是用来展开和访问可选变量 `john``unit4A` 中的实例,这样实例的属性才能被赋值:
现在你能够将这两个实例关联在一起,这样人就能有公寓住了,而公寓也有了房客。注意感叹号是用来解包和访问可选变量 `john``unit4A` 中的实例,这样实例的属性才能被赋值:
```swift
john!.apartment = unit4A
@ -171,7 +171,7 @@ Swift 提供了两种办法用来解决你在使用类的属性时所遇到的
因为弱引用不会保持所引用的实例即使引用存在实例也有可能被销毁。因此ARC 会在引用的实例被销毁后自动将其弱引用赋值为 `nil`。并且因为弱引用需要在运行时允许被赋值为 `nil`,所以它们会被定义为可选类型变量,而不是常量。
你可以像其他可选值一样,检查弱引用的值是否存在,你将永远不会访问已销毁的实例的引用。
你可以像其他可选值一样,检查弱引用的值是否存在,这样可以避免访问已销毁的实例的引用。
> 注意
>
@ -230,7 +230,7 @@ unit4A = nil
// 打印“Apartment 4A is being deinitialized”
```
由于再也没有指向 `Person` 实例的强引用,该实例会被销毁:
由于再也没有指向 `Apartment` 实例的强引用,该实例会被销毁:
![](https://docs.swift.org/swift-book/_images/weakReference03_2x.png)
@ -331,7 +331,7 @@ john = nil
然而,存在着第三种场景,在这种场景中,两个属性都必须有值,并且初始化完成后永远不会为 `nil`。在这种场景中,需要一个类使用无主属性,而另外一个类使用隐式解包可选值属性。
这使两个属性在初始化完成后能被直接访问(不需要可选展开),同时避免了循环引用。这一节将为你展示如何建立这种关系。
这使两个属性在初始化完成后能被直接访问(不需要可选解包),同时避免了循环引用。这一节将为你展示如何建立这种关系。
下面的例子定义了两个类,`Country``City`,每个类将另外一个类的实例保存为属性。在这个模型中,每个国家必须有首都,每个城市必须属于一个国家。为了实现这种关系,`Country` 类拥有一个 `capitalCity` 属性,而 `City` 类有一个 `country` 属性:
@ -357,13 +357,13 @@ class City {
为了建立两个类的依赖关系,`City` 的构造器接受一个 `Country` 实例作为参数,并且将实例保存到 `country` 属性。
`Country` 的构造器调用了 `City` 的构造器。然而,只有 `Country` 的实例完全初始化后,`Country` 的构造器才能把 `self` 传给 `City` 的构造器。在 [两段式构造过程](./14_Initialization.md#two_phase_initialization) 中有具体描述。
`Country` 的构造器调用了 `City` 的构造器。然而,只有 `Country` 的实例完全初始化后,`Country` 的构造器才能把 `self` 传给 `City` 的构造器。在 [两段式构造过程](./14_Initialization.md#two-phase-initialization) 中有具体描述。
为了满足这种需求,通过在类型结尾处加上感叹号(`City!`)的方式,将 `Country``capitalCity` 属性声明为隐式解包可选值类型的属性。这意味着像其他可选类型一样,`capitalCity` 属性的默认值为 `nil`,但是不需要展开它的值就能访问它。在 [隐式解包可选值](./01_The_Basics.md#implicityly_unwrapped_optionals) 中有描述。
为了满足这种需求,通过在类型结尾处加上感叹号(`City!`)的方式,将 `Country``capitalCity` 属性声明为隐式解包可选值类型的属性。这意味着像其他可选类型一样,`capitalCity` 属性的默认值为 `nil`,但是不需要解包它的值就能访问它。在 [隐式解包可选值](./01_The_Basics.md#implicityly-unwrapped-optionals) 中有描述。
由于 `capitalCity` 默认值为 `nil`,一旦 `Country` 的实例在构造器中给 `name` 属性赋值后,整个初始化过程就完成了。这意味着一旦 `name` 属性被赋值后,`Country` 的构造器就能引用并传递隐式的 `self``Country` 的构造器在赋值 `capitalCity` 时,就能将 `self` 作为参数传递给 `City` 的构造器。
上的意义在于你可以通过一条语句同时创建 `Country``City` 的实例,而不产生循环强引用,并且 `capitalCity` 的属性能被直接访问,而不需要通过感叹号来展开它的可选值:
的意义在于你可以通过一条语句同时创建 `Country``City` 的实例,而不产生循环强引用,并且 `capitalCity` 的属性能被直接访问,而不需要通过感叹号来解包它的可选值:
```swift
var country = Country(name: "Canada", capitalName: "Ottawa")
@ -453,7 +453,7 @@ print(paragraph!.asHTML())
![](https://docs.swift.org/swift-book/_images/closureReferenceCycle01_2x.png)
实例的 `asHTML` 属性持有闭包的强引用。但是,闭包在其闭包体内使用了 `self`(引用了 `self.name``self.text`),因此闭包捕获了 `self`,这意味着闭包又反过来持有了 `HTMLElement` 实例的强引用。这样两个对象就产生了循环强引用。(更多关于闭包捕获值的信息,请参考 [值捕获](./07_Closures.md#capturing_values))。
实例的 `asHTML` 属性持有闭包的强引用。但是,闭包在其闭包体内使用了 `self`(引用了 `self.name``self.text`),因此闭包捕获了 `self`,这意味着闭包又反过来持有了 `HTMLElement` 实例的强引用。这样两个对象就产生了循环强引用。(更多关于闭包捕获值的信息,请参考 [值捕获](./07_Closures.md#capturing-values))。
> 注意
>
@ -477,13 +477,14 @@ paragraph = nil
### 定义捕获列表 {#defining-a-capture-list}
捕获列表中的每一项都由一对元素组成,一个元素是 `weak``unowned` 关键字,另一个元素是类实例的引用(例如 `self`)或初始化过的变量(如 `delegate = self.delegate!`)。这些项在方括号中用逗号分开。
捕获列表中的每一项都由一对元素组成,一个元素是 `weak``unowned` 关键字,另一个元素是类实例的引用(例如 `self`)或初始化过的变量(如 `delegate = self.delegate`)。这些项在方括号中用逗号分开。
如果闭包有参数列表和返回类型,把捕获列表放在它们前面:
```swift
lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
lazy var someClosure = {
[unowned self, weak delegate = self.delegate]
(index: Int, stringToProcess: String) -> String in
// 这里是闭包的函数体
}
```
@ -491,8 +492,8 @@ lazy var someClosure: (Int, String) -> String = {
如果闭包没有指明参数列表或者返回类型,它们会通过上下文推断,那么可以把捕获列表和关键字 `in` 放在闭包最开始的地方:
```swift
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
lazy var someClosure = {
[unowned self, weak delegate = self.delegate] in
// 这里是闭包的函数体
}
```
@ -557,4 +558,4 @@ paragraph = nil
// 打印“p is being deinitialized”
```
你可以查看 [捕获列表](../chapter3/04_Expressions.html) 章节,获取更多关于捕获列表的信息。
你可以查看 [捕获列表](../03_language_reference/04_Expressions.md) 章节,获取更多关于捕获列表的信息。

View File

@ -1,14 +1,14 @@
# 访问控制
*访问控制*可以限定其它源文件或模块中的代码对你的代码的访问级别。这个特性可以让我们隐藏代码的一些实现细节,并且可以为其他人可以访问和使用的代码提供接口
*访问控制*可以限定其它源文件或模块对你的代码的访问。这个特性可以让隐藏代码的实现细节,并且能提供一个接口来让别人访问和使用的代码。
你可以明确地给单个类型(类、结构体、枚举)设置访问级别,也可以给这些类型的属性、方法、构造器、下标等设置访问级别。协议也可以被限定在一定的范围内使用,包括协议里的全局常量、变量和函数。
你可以明确地给单个类型(类、结构体、枚举)设置访问级别,也可以给这些类型的属性、方法、构造器、下标等设置访问级别。协议也可以被限定在一定访问级别的范围内使用,包括协议里的全局常量、变量和函数。
Swift 不仅提供了多种不同的访问级别,还为某些典型场景提供了默认的访问级别,这样就不需要我们在每段代码中都申明显式访问级别。其实,如果只是开发一个单 target 的应用程序,我们完全可以不用显式声明代码的访问级别。
Swift 不仅提供了多种不同的访问级别,还为某些典型场景提供了默认的访问级别,这样就不需要我们在每段代码中都显式声明访问级别。如果只是开发一个单 target 的应用程序,完全可以不用显式声明代码的访问级别。
> 注意
>
> 为了简单起见,对于代码中可以设置访问级别的特性(属性、基本类型、函数等),在下面的章节中我们会称之为“实体”。
> 为了简单起见,对于代码中可以设置访问级别的特性(属性、基本类型、函数等),在下面的章节中我们会统一称之为“实体”。
## 模块和源文件 {#modules-and-source-files}
@ -16,29 +16,22 @@ Swift 中的访问控制模型基于模块和源文件这两个概念。
*模块*指的是独立的代码单元,框架或应用程序会作为一个独立的模块来构建和发布。在 Swift 中,一个模块可以使用 `import` 关键字导入另外一个模块。
在 Swift 中Xcode 的每个 target例如框架或应用程序都被当作独立的模块处理。如果你是为了实现某个通用的功能或者是为了封装一些常用方法而将代码打包成独立的框架这个框架就是 Swift 中的一个模块。当它被导入到某个应用程序或者其他框架时,框架内容都将属于这个独立的模块。
在 Swift 中Xcode 的每个 target例如框架或应用程序都被当作独立的模块处理。如果你是为了实现某个通用的功能或者是为了封装一些常用方法而将代码打包成独立的框架这个框架就是 Swift 中的一个模块。当它被导入到某个应用程序或者其他框架时,框架内容都将属于这个独立的模块。
*源文件*就是 Swift 中的源代码文件,它通常属于一个模块,即一个应用程序或框架。尽管我们一般会将不同的类型分别定义在不同的源文件中,但是同一个源文件也可以包含多个类型、函数之类的定义。
*源文件* 就是 Swift 模块中的源代码文件(实际上,源文件属于一个应用程序或框架。尽管我们一般会将不同的类型分别定义在不同的源文件中,但是同一个源文件也可以包含多个类型、函数的定义。
## 访问级别 {#access-levels}
Swift 为代码中的实体提供了五种不同的*访问级别*。这些访问级别不仅与源文件中定义的实体相关,同时也与源文件所属的模块相关。
- *Open**Public* 级别可以让实体被同一模块源文件中的所有实体访问,在模块外也可以通过导入该模块来访问源文件里的所有实体。通常情况下,你会使用 Open 或 Public 级别来指定框架的外部接口。Open 和 Public 的区别在后面会提到。
- *Internal* 级别让实体被同一模块源文件中的任何实体访问,但是不能被模块外的实体访问。通常情况下,如果某个接口只在应用程序或框架内部使用,就可以将其设置为 Internal 级别。
- *File-private* 限制实体只能在其定义的文件内部访问。如果功能的部分细节只需要在文件内使用时,可以使用 File-private 来将其隐藏。
- *Private* 限制实体只能在其定义的作用域,以及同一文件内的 extension 访问。如果功能的部分细节只需要在当前作用域内使用时,可以使用 Private 来将其隐藏。
- *open**public* 级别可以让实体被同一模块源文件中的所有实体访问,在模块外也可以通过导入该模块来访问源文件里的所有实体。通常情况下,你会使用 open 或 public 级别来指定框架的外部接口。open 和 public 的区别在后面会提到。
- *internal* 级别让实体被同一模块源文件中的任何实体访问,但是不能被模块外的实体访问。通常情况下,如果某个接口只在应用程序或框架内部使用,就可以将其设置为 internal 级别。
- *fileprivate* 限制实体只能在其定义的文件内部访问。如果功能的部分实现细节只需要在文件内使用时,可以使用 fileprivate 来将其隐藏。
- *private* 限制实体只能在其定义的作用域,以及同一文件内的 extension 访问。如果功能的部分细节只需要在当前作用域内使用时,可以使用 private 来将其隐藏。
Open 为最高访问级别(限制最少),Private 为最低访问级别(限制最多)。
open 为最高访问级别(限制最少),private 为最低访问级别(限制最多)。
Open 只能作用于类和类的成员,它和 Public 的区别如下:
* Public 或者其它更严访问级别的类,只能在其定义的模块内部被继承。
* Public 或者其它更严访问级别的类成员,只能在其定义的模块内部的子类中重写。
* Open 的类,可以在其定义的模块中被继承,也可以在引用它的模块中被继承。
* Open 的类成员,可以在其定义的模块中子类中重写,也可以在引用它的模块中的子类重写。
把一个类标记为 `open`,明确的表示你已经充分考虑过外部模块使用此类作为父类的影响,并且设计好了你的类的代码了。
open 只能作用于类和类的成员,它和 public 的区别主要在于 open 限定的类和成员能够在模块外能被继承和重写,在下面的 [子类](#subclassing) 这一节中有详解。将类的访问级别显式指定为 `open` 表明你已经设计好了类的代码,并且充分考虑过这个类在其他模块中用作父类时的影响。
### 访问级别基本原则 {#guiding-principle-of-access-levels}
@ -46,22 +39,22 @@ Swift 中的访问级别遵循一个基本原则:*实体不能定义在具有
例如:
- 一个 Public 的变量,其类型的访问级别不能是 InternalFile-private 或是 Private。因为无法保证变量的类型在使用变量的地方也具有访问权限。
- 一个 public 的变量,其类型的访问级别不能是 internalfileprivate 或是 private。因为无法保证变量的类型在使用变量的地方也具有访问权限。
- 函数的访问级别不能高于它的参数类型和返回类型的访问级别。因为这样就会出现函数可以在任何地方被访问,但是它的参数类型和返回类型却不可以的情况。
关于此原则在各种情况下的具体表现,将在下文有所体现。
### 默认访问级别 {#default-access-levels}
如果你没有为代码中的实体显式指定访问级别,那么它们默认为 `internal` 级别(有一些例外情况,稍后会进行说明)。因此,在大多数情况下,我们不需要显指定实体的访问级别。
代码中所有的实体,如果你不显式指定它们的访问级别,那么它们将都有一个 `internal` 的默认访问级别(有一些例外情况,本文稍后会说明)。因此,多数情况下不需要显指定实体的访问级别。
### 单 target 应用程序的访问级别 {#access-levels-for-single-target-apps}
当你编写一个单目标应用程序时,应用的所有功能都是为该应用服务,而不需要提供给其他应用或者模块使用,所以我们不需要明确设置访问级别,使用默认的访问级别 Internal 即可。但是,你也可以使用 `fileprivate` 访问`private` 访问级别,用于隐藏一些功能的实现细节。
当你编写一个单 target 应用程序时,应用的所有功能都是为该应用服务,而不需要提供给其他应用或者模块使用,所以不需要明确设置访问级别,使用默认的访问级别 internal 即可。但是,你也可以使用 `fileprivate``private` 访问级别,用于隐藏一些功能的实现细节。
### 框架的访问级别 {#access-levels-for-frameworks}
当你开发框架时,就需要把一些对外的接口定义为 Open 或 Public以便使用者导入该框架后可以正常使用其功能。这些被你定义为对外的接口就是这个框架的 API。
当你开发框架时,就需要把一些对外的接口定义为 open 或 public 访问级别,以便使用者导入该框架后可以正常使用其功能。这些被你定义为对外的接口,就是这个框架的 API。
> 注意
>
@ -87,7 +80,7 @@ fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}
```
除非专门指定,否则实体默认的访问级别为 `internal`,可以查阅 [默认访问级别](#default_access_levels) 这一节。这意味着在不使用修饰符显式声明访问级别的情况下,`SomeInternalClass``someInternalConstant` 仍然拥有隐式`internal`
除非专门指定,否则实体默认的访问级别为 `internal`,可以查阅 [默认访问级别](#default-access-levels) 这一节。这意味着在不使用修饰符显式声明访问级别的情况下,`SomeInternalClass``someInternalConstant`访问级别是 `internal`
```swift
class SomeInternalClass {} // 隐式 internal
@ -96,7 +89,7 @@ var someInternalConstant = 0 // 隐式 internal
## 自定义类型 {#custom-types}
如果想为一个自定义类型指定访问级别,在定义类型时进行指定即可。新类型只能在它的访问级别限制范围内使用。例如,你定义了一个 `fileprivate` 级别的类,那这个类就只能在定义它的源文件中使用,可以作为属性类型、函数参数类型或者返回类型等等。
如果想为一个自定义类型指定访问级别,在定义类型时进行指定即可。新类型只能在它的访问级别限制范围内使用。例如,你定义了一个 `fileprivate` 级别的类,那这个类就只能在定义它的源文件中使用,可以作为属性类型、函数参数类型或者返回类型等等。
一个类型的访问级别也会影响到类型*成员*(属性、方法、构造器、下标)的默认访问级别。如果你将类型指定为 `private` 或者 `fileprivate` 级别,那么该类型的所有成员的默认访问级别也会变成 `private` 或者 `fileprivate` 级别。如果你将类型指定为 `internal``public`(或者不明确指定访问级别,而使用默认的 `internal` ),那么该类型的所有成员的默认访问级别将是 `internal`
@ -127,13 +120,15 @@ private class SomePrivateClass { // 显式 private 类
func somePrivateMethod() {} // 隐式 private 类成员
}
```
### 元组类型 {#tuple-types}
元组的访问级别将由元组中访问级别最严格的类型来决定。例如,如果你构建了一个包含两种不同类型的元组,其中一个类型为 `internal`,另一个类型为 `private`,那么这个元组的访问级别为 `private`
> 注意
>
> 元组不同于类、结构体、枚举、函数那样有单独的定义。元组的访问级别是在它被使用时自动推断出的,而无法明确指定。
> 元组不同于类、结构体、枚举、函数那样有单独的定义。一个元组的访问级别由元组中元素的访问级别来决定的,不能被显示指定。
### 函数类型 {#function-types}
@ -147,9 +142,9 @@ func someFunction() -> (SomeInternalClass, SomePrivateClass) {
}
```
我们可以看到,这个函数的返回类型是一个元组,该元组中包含两个自定义的类(可查阅 [自定义类型](#custom_types))。其中一个类的访问级别是 `internal`,另一个的访问级别是 `private`,所以根据元组访问级别的原则,该元组的访问级别是 `private`(元组的访问级别与元组中访问级别最低的类型一致)。
我们可以看到,这个函数的返回类型是一个元组,该元组中包含两个自定义的类(可查阅 [自定义类型](#custom-types))。其中一个类的访问级别是 `internal`,另一个的访问级别是 `private`,所以根据元组访问级别的原则,该元组的访问级别是 `private`(元组的访问级别与元组中访问级别最低的类型一致)。
因为该函数返回类型的访问级别是 `private`,所以你必须使用 `private` 修饰符明确指定该函数的访问级别:
因为该函数返回类型的访问级别是 `private`,所以你必须使用 `private` 修饰符明确指定该函数的访问级别:
```swift
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
@ -163,7 +158,7 @@ private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
枚举成员的访问级别和该枚举类型相同,你不能为枚举成员单独指定不同的访问级别。
比如下面的例子,枚举 `CompassPoint` 被明确指定为 `public`,那么它的成员 `North``South``East``West` 的访问级别同样也是 `public`
比如下面的例子,枚举 `CompassPoint` 被明确指定为 `public`,那么它的成员 `north``south``east``west` 的访问级别同样也是 `public`
```swift
public enum CompassPoint {
@ -180,15 +175,15 @@ public enum CompassPoint {
### 嵌套类型 {#nested-types}
如果在 `private` 的类型中定义嵌套类型,那么该嵌套类型就自动拥有 `private` 访问级别。如果在 `public` 或者 `internal` 级别的类型中定义嵌套类型,那么嵌套类型自动拥有 `internal` 访问级别。如果想让嵌套类型拥有 `public` 访问级别,那么需要明确指定该嵌套类型的访问级别。
嵌套类型的访问级别和包含它的类型的访问级别相同,嵌套类型是 public 的情况除外。在一个 public 的类型中定义嵌套类型,那么嵌套类型自动拥有 `internal` 访问级别。如果想让嵌套类型拥有 `public` 访问级别,那么必须显式指定该嵌套类型的访问级别为 public
## 子类 {#subclassing}
子类的访问级别不得高于父类的访问级别。例如,父类的访问级别是 `internal`,子类的访问级别就不能是 `public`
你可以继承同一模块中的所有有访问权限的类,也可以继承不同模块中被 open 修饰的类。一个子类的访问级别不得高于父类的访问级别。例如,父类的访问级别是 `internal`,子类的访问级别就不能是 `public`
此外,你可以在符合当前访问级别的条件下重写任意类成员(方法、属性、构造器、下标等)。
此外,在同一模块中,你可以在符合当前访问级别的条件下重写任意类成员(方法、属性、构造器、下标等)。在不同模块中,你可以重写类中被 open 修饰的成员。
可以通过重写为继承来的类成员提供更高的访问级别。下面的例子中,类 `A` 的访问级别是 `public`,它包含一个方法 `someMethod()`,访问级别为 `private`。类 `B` 继承自类 `A`,访问级别为 `internal`,但是在类 `B` 中重写了类 `A` 中访问级别为 `private` 的方法 `someMethod()`,并重新指定为 `internal` 级别。通过这种方式,我们就可以将某类中 `private` 级别的类成员重新指定为更高的访问级别,以便其他人使用:
可以通过重写给所继承类的成员提供更高的访问级别。下面的例子中,类 `A` 的访问级别是 `public`,它包含一个方法 `someMethod()`,访问级别为 `fileprivate`。类 `B` 继承自类 `A`,访问级别为 `internal`,但是在类 `B` 中重写了类 `A` 中访问级别为 `fileprivate` 的方法 `someMethod()`,并重新指定为 `internal` 级别。通过这种方式,我们就可以将某类中 `fileprivate` 级别的类成员重新指定为更高的访问级别,以便其他人使用:
```swift
public class A {
@ -200,7 +195,7 @@ internal class B: A {
}
```
我们甚至可以在子类中,用子类成员去访问访问级别更低的父类成员,只要这一操作在相应访问级别的限制范围内(也就是说,在同一源文件中访问父类 `private` 级别的成员,在同一模块内访问父类 `internal` 级别的成员):
我们甚至可以在子类中,用子类成员去访问访问级别更低的父类成员,只要这一操作在相应访问级别的限制范围内(也就是说,在同一源文件中访问父类 `fileprivate` 级别的成员,在同一模块内访问父类 `internal` 级别的成员):
```swift
public class A {
@ -234,7 +229,7 @@ private var privateInstance = SomePrivateClass()
> 注意
>
> 这个规则同时适用于存储型属性和计算型属性。即使你不明确指定存储型属性的 `Getter``Setter`Swift 也会隐式地为其创建 `Getter``Setter`,用于访问该属性的后备存储。使用 `fileprivate(set)``private(set)``internal(set)` 可以改变 `Setter` 的访问级别,这对计算型属性也同样适用。
> 这个规则同时适用于存储型属性和计算型属性。即使你不明确指定存储型属性的 `Getter``Setter`Swift 也会隐式地为其创建 `Getter``Setter`,用于访问该属性的存储内容。使用 `fileprivate(set)``private(set)``internal(set)` 可以改变 `Setter` 的访问级别,这对计算型属性也同样适用。
下面的例子中定义了一个名为 `TrackedString` 的结构体,它记录了 `value` 属性被修改的次数:
@ -282,13 +277,13 @@ public struct TrackedString {
## 构造器 {#initializers}
自定义构造器的访问级别可以低于或等于其所属类型的访问级别。唯一的例外是 [必要构造器](./14_Initialization.md#required_initializers),它的访问级别必须和所属类型的访问级别相同。
自定义构造器的访问级别可以低于或等于其所属类型的访问级别。唯一的例外是 [必要构造器](./14_Initialization.md#required-initializers),它的访问级别必须和所属类型的访问级别相同。
如同函数或方法的参数,构造器参数的访问级别也不能低于构造器本身的访问级别。
### 默认构造器 {#default-initializers}
如 [默认构造器](./14_Initialization.md#default_initializers) 所述Swift 会为结构体和类提供一个默认的无参数的构造器,只要它们为所有存储型属性设置了默认初始值,并且未提供自定义的构造器。
如 [默认构造器](./14_Initialization.md#default-initializers) 所述Swift 会为结构体和类提供一个默认的无参数的构造器,只要它们为所有存储型属性设置了默认初始值,并且未提供自定义的构造器。
默认构造器的访问级别与所属类型的访问级别相同,除非类型的访问级别是 `public`。如果一个类型被指定为 `public` 级别,那么默认构造器的访问级别将为 `internal`。如果你希望一个 `public` 级别的类型也能在其他模块中使用这种无参数的默认构造器,你只能自己提供一个 `public` 访问级别的无参数构造器。
@ -300,17 +295,17 @@ public struct TrackedString {
## 协议 {#protocols}
如果想为一个协议类型明确地指定访问级别,在定义协议时指定即可。这将限制该协议只能在适当的访问级别范围内被遵循。
如果想为一个协议类型明确地指定访问级别,在声明协议时指定即可。这将限制该协议只能在适当的访问级别范围内被遵循。
协议中的每一个要求都具有和该协议相同的访问级别。你不能将协议中的要求设置为其他访问级别。这样才能确保该协议的所有要求对于任意遵循者都可用。
协议中的每个方法或属性都必须具有和该协议相同的访问级别。你不能将协议中的方法或属性设置为其他访问级别。这样才能确保该协议的所有方法或属性对于任意遵循者都可用。
> 注意
>
> 如果你定义了一个 `public` 访问级别的协议,那么该协议的所有实现也会是 `public` 访问级别。这一点不同于其他类型,例如,类型是 `public` 访问级别时,其成员的访问级别却只是 `internal`
> 如果你定义了一个 `public` 访问级别的协议,那么该协议的所有实现也会是 `public` 访问级别。这一点不同于其他类型,例如,类型是 `public` 访问级别时,其成员的访问级别却只是 `internal`
### 协议继承 {#protocol-inheritance}
如果定义了一个继承自其他协议的新协议,那么新协议拥有的访问级别最高也只能和被继承协议的访问级别相同。例如,你不能将继承自 `internal` 协议的新协议定`public` 协议。
如果定义了一个继承自其他协议的新协议,那么新协议拥有的访问级别最高也只能和被继承协议的访问级别相同。例如,你不能将继承自 `internal` 协议的新协议访问级别指定为 `public` 协议。
### 协议遵循 {#protocol-conformance}
@ -326,9 +321,9 @@ public struct TrackedString {
## Extension {#extensions}
Extension 可以在访问级别允许的情况下对类、结构体、枚举进行扩展。Extension 的成员具有和原始类型成员一致的访问级别。例如,你使用 extension 扩展了一个 `public` 或者 `internal` 类型extension 中的成员就默认使用 `internal` 访问级别,和原始类型中的成员一致。如果你使用 extension 扩展了一个 `private` 类型,则 extension 的成员默认使用 `private` 访问级别。
Extension 可以在访问级别允许的情况下对类、结构体、枚举进行扩展。Extension 的新增成员具有和原始类型成员一致的访问级别。例如,你使用 extension 扩展了一个 `public` 或者 `internal` 类型,extension 中的成员就默认使用 `internal` 访问级别。如果你使用 extension 扩展一个 `fileprivate` 类型,则 extension 中的成员默认使用 `fileprivate` 访问级别。如果你使用 extension 扩展了一个 `private` 类型,则 extension 的成员默认使用 `private` 访问级别。
或者,你可以明确指定 extension 的访问级别(例如,`private extension`),从而给该 extension 中的所有成员指定一个新的默认访问级别。这个新的默认访问级别仍然可以被单独指定的访问级别所覆盖。
或者,你可以通过修饰语重新指定 extension 的默认访问级别(例如,`private`),从而给该 extension 中的所有成员指定一个新的默认访问级别。这个新的默认访问级别仍然可以被单独成员指定的访问级别所覆盖。
如果你使用 extension 来遵循协议的话,就不能显式地声明 extension 的访问级别。extension 每个 protocol 要求的实现都默认使用 protocol 的访问级别。
@ -340,7 +335,7 @@ Extension 可以在访问级别允许的情况下对类、结构体、枚举进
- 在 extension 里声明一个私有成员,在同一文件的另一个 extension 里访问。
- 在 extension 里声明一个私有成员,在同一文件的类型声明里访问。
这意味着你可以像组织的代码去使用 extension而且不受私有成员的影响。例如给定下面这样一个简单的协议
这意味着你可以使用 extension 来组织你的代码,而且不受私有成员的影响。例如,给定下面这样一个简单的协议:
```swift
protocol SomeProtocol {
@ -368,7 +363,7 @@ extension SomeStruct: SomeProtocol {
## 类型别名 {#type-aliases}
你定义的任何类型别名都会被当作不同的类型,以便于进行访问控制。类型别名的访问级别不可高于其表示的类型的访问级别。例如,`private` 级别的类型别名可以作为 `private``file-private``internal``public` 或者 `open` 类型的别名,但是 `public` 级别的类型别名只能作为 `public` 类型的别名,不能作为 `internal``file-private``private` 类型的别名。
你定义的任何类型别名都会被当作不同的类型,以便于进行访问控制。类型别名的访问级别不可高于其表示的类型的访问级别。例如,`private` 级别的类型别名可以作为 `private``fileprivate``internal``public` 或者 `open` 类型的别名,但是 `public` 级别的类型别名只能作为 `public` 类型的别名,不能作为 `internal``fileprivate``private` 类型的别名。
> 注意
>

View File

@ -210,7 +210,7 @@ unsignedOverflow = unsignedOverflow &- 1
![Art/overflowUnsignedSubtraction_2x.png](https://docs.swift.org/swift-book/_images/overflowUnsignedSubtraction_2x.png)
溢出也会发生在有符号整型上。针对有符号整型的所有溢出加法或者减法运算都是按位运算的方式执行的,符号位也需要参与计算,正如 [按位左移、右移运算符](#bitwise_left_and_right_shift_operators) 所描述的。
溢出也会发生在有符号整型上。针对有符号整型的所有溢出加法或者减法运算都是按位运算的方式执行的,符号位也需要参与计算,正如 [按位左移、右移运算符](#bitwise-left-and-right-shift-operators) 所描述的。
```Swift
var signedOverflow = Int8.min
@ -219,7 +219,7 @@ signedOverflow = signedOverflow &- 1
// 此时 signedOverflow 等于 127
```
`Int8` 型整数能容纳的最小值是 `-128`,以二进制表示即 `10000000`。当使用溢出减法运算符对其进行减 `1` 运算时,符号位被翻转,得到二进制数值 `01111111`,也就是十进制数值的 `127`,这个值也是 `Int8` 型整所能容纳的最大值。
`Int8` 型整数能容纳的最小值是 `-128`,以二进制表示即 `10000000`。当使用溢出减法运算符对其进行减 `1` 运算时,符号位被翻转,得到二进制数值 `01111111`,也就是十进制数值的 `127`,这个值也是 `Int8` 型整所能容纳的最大值。
![Art/overflowSignedSubtraction_2x.png](https://docs.swift.org/swift-book/_images/overflowSignedSubtraction_2x.png)
@ -266,7 +266,7 @@ signedOverflow = signedOverflow &- 1
因此计算结果为 `17`
有关 Swift 标准库提供的操作符信息,包括操作符优先级组和结性设置的完整列表,请参见 [操作符声明](https://developer.apple.com/documentation/swift/operator_declarations)。
有关 Swift 标准库提供的操作符信息,包括操作符优先级组和结性设置的完整列表,请参见 [操作符声明](https://developer.apple.com/documentation/swift/operator_declarations)。
> 注意
>
@ -389,32 +389,11 @@ if twoThree == anotherTwoThree {
// 打印“These two vectors are equivalent.”
```
多数简单情况下,可以使用 Swift 为您提供的等价运算符默认实现。Swift 为以下数种自定义类型提供等价运算符的默认实现:
- 只拥有存储属性,并且它们全都遵循 `Equatable` 协议的结构体
- 只拥有关联类型,并且它们全都遵循 `Equatable` 协议的枚举
- 没有关联类型的枚举
在类型原始的声明中声明遵循 `Equatable` 来接收这些默认实现。
下面为三维位置向量 `(x, y, z)` 定义的 `Vector3D` 结构体,与 `Vector2D` 类似。由于 `x``y``z` 属性都是 `Equatable` 类型,`Vector3D` 获得了默认的等价运算符实现。
```Swift
struct Vector3D: Equatable {
var x = 0.0, y = 0.0, z = 0.0
}
let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
print("These two vectors are also equivalent.")
}
// 打印“These two vectors are also equivalent.”
```
多数简单情况下,可以 Swift 合成等价运算符的实现,详见 [使用合成实现来采纳协议](./21_Protocols.md#adopting-a-protocol-using-a-synthesized-implementation)。
## 自定义运算符 {#custom-operators}
除了实现标准运算符,在 Swift 中还可以声明和实现*自定义运算符*。可以用来自定义运算符的字符列表请参考 [运算符](../chapter3/02_Lexical_Structure.html#operators)。
除了实现标准运算符,在 Swift 中还可以声明和实现*自定义运算符*。可以用来自定义运算符的字符列表请参考 [运算符](../03_language_reference/02_Lexical_Structure.md#operators)。
新的运算符要使用 `operator` 关键字在全局作用域内进行定义,同时还要指定 `prefix``infix` 或者 `postfix` 修饰符:
@ -440,7 +419,7 @@ let afterDoubling = +++toBeDoubled
### 自定义中缀运算符的优先级 {#precedence-and-associativity-for-custom-infix-operators}
每个自定义中缀运算符都属于某个优先级组。优先级组指定了这个运算符相对于其他中缀运算符的优先级和结合性。[优先级和结合性](#precedence_and_associativity) 中详细阐述了这两个特性是如何对中缀运算符的运算产生影响的。
每个自定义中缀运算符都属于某个优先级组。优先级组指定了这个运算符相对于其他中缀运算符的优先级和结合性。[优先级和结合性](#precedence-and-associativity) 中详细阐述了这两个特性是如何对中缀运算符的运算产生影响的。
而没有明确放入某个优先级组的自定义中缀运算符将会被放到一个默认的优先级组内,其优先级高于三元运算符。
@ -459,7 +438,7 @@ let plusMinusVector = firstVector +- secondVector
// plusMinusVector 是一个 Vector2D 实例,并且它的值为 (4.0, -2.0)
```
这个运算符把两个向量的 `x` 值相加,同时从第一个向量的 `y` 中减去第二个向量的 `y` 。因为它本质上是属于“相加型”运算符,所以将它放置在 `+``-` 等默认中缀“相加型”运算符相同的优先级组中。关于 Swift 标准库提供的运算符,以及完整的运算符优先级组和结合性设置,请参考 [运算符声明](https://developer.apple.com/documentation/swift/operator_declarations)。而更多关于优先级组以及自定义操作符和优先级组的语法,请参考 [运算符声明](./06_Declarations.md#operator_declaration)。
这个运算符把两个向量的 `x` 值相加,同时从第一个向量的 `y` 中减去第二个向量的 `y` 。因为它本质上是属于“相加型”运算符,所以将它放置在 `+``-` 等默认中缀“相加型”运算符相同的优先级组中。关于 Swift 标准库提供的运算符,以及完整的运算符优先级组和结合性设置,请参考 [运算符声明](https://developer.apple.com/documentation/swift/operator_declarations)。而更多关于优先级组以及自定义操作符和优先级组的语法,请参考 [运算符声明](../03_language_reference/06_Declarations.md#operator-declaration)。
> 注意
>

View File

@ -1,3 +1,3 @@
# Swift 教程
# Swift 语言教程
本章介绍了 Swift 的各种特性及其使用方法,是全书的核心部分。

View File

@ -19,14 +19,14 @@ Swift 语言相对较小,这是由于 Swift 代码中常用的类型、函数
> getter-setter 方法块语法
>
> *getter-setter 方法块* → { [*getter 子句*](./06_Declarations.md#getter-clause) [*setter 子句*](./06_Declarations.md#setter-clause)<sub>可选</sub> } | { [*setter 子句*](./06_Declarations.md#setter-clause) [*getter 子句*](./06_Declarations.md#getter-clause) }
>
> *getter-setter 方法块* → { [getter 子句](./06_Declarations.md#getter-clause) [setter 子句](./06_Declarations.md#setter-clause)<sub>可选</sub> } | { [setter 子句](./06_Declarations.md#setter-clause) [getter 子句](./06_Declarations.md#getter-clause) }
这个定义表明,一个 getter-setter 方法块可以由一个 getter 分句后跟一个可选的 setter 分句构成,然后用大括号括起来,或者由一个 setter 分句后跟一个 getter 分句构成,然后用大括号括起来。上述的语法产式等价于下面的两个语法产式,
> getter-setter 方法块语法
>
> getter-setter 方法块 → { [*getter 子句*](./06_Declarations.md#getter-clause) [*setter 子句*](./06_Declarations.md#setter-clause)<sub>可选</sub> }
> getter-setter 方法块 → { [getter 子句](./06_Declarations.md#getter-clause) [setter 子句](./06_Declarations.md#setter-clause)<sub>可选</sub> }
>
> getter-setter 方法块 → { [*setter 子句*](./06_Declarations.md#setter-clause) [*getter 子句*](./06_Declarations.md#getter-clause) }
> getter-setter 方法块 → { [setter 子句](./06_Declarations.md#setter-clause) [getter 子句](./06_Declarations.md#getter-clause) }
>

View File

@ -0,0 +1,645 @@
# 词法结构Lexical Structure
Swift 的*“词法结构lexical structure”* 描述了能构成该语言中有效符号token的字符序列。这些合法符号组成了语言中最底层的构建基块并在之后的章节中用于描述语言的其他部分。一个合法符号由一个标识符identifier、关键字keyword、标点符号punctuation、字面量literal或运算符operator组成。
通常情况下,符号是考虑了输入文本中最长可能的子字符串,并被随后将介绍的语法约束,根据 Swift 源文件的字符生成的。这种方法称为*“最长匹配longest match”*,或者*“最大适合maximal munch”*。
## 空白与注释 {#whitespace}
空白whitespace有两个用途分隔源文件中的符号以及帮助区分运算符属于前缀还是后缀参见 [运算符](#operators)在其他情况下空白则会被忽略。以下的字符会被当作空白空格U+0020、换行符U+000A、回车符U+000D、水平制表符U+0009、垂直制表符U+000B、换页符U+000C以及空字符U+0000
注释被编译器当作空白处理。单行注释由 `//` 开始直至遇到换行符U+000A或者回车符U+000D。多行注释由 `/*` 开始,以 `*/` 结束。多行注释允许嵌套,但注释标记必须成对出现。
注释可以包含其他的格式和标记,如 [标记格式参考](https://developer.apple.com/library/archive/documentation/Xcode/Reference/xcode_markup_formatting_ref/index.html)中所述。
> 空白语法
>
> *空白* → [空白项](#whitespace-item) [空白](#whitespace)<sub>可选</sub>
>
#### whitespace-item {#whitespace-item}
>
> *空白项* → [断行符](#line-break)
>
> *空白项* → [注释](#comment)
>
> *空白项* → [多行注释](#multiline-comment)
>
> *空白项* → U+0000U+0009U+000BU+000C 或者 U+0020
>
>
#### line-break {#line-break}
>
> *断行符* → U+000A
>
> *断行符* → U+000D
>
> *断行符* → U+000D 接着是 U+000A
>
>
#### comment {#comment}
>
> *注释* → // [注释内容](#comment-text) [断行符](#line-break)
>
>
#### multiline-comment {#multiline-comment}
>
> *多行注释* → `/*` [多行注释内容](#multiline-commnet-text) `*/`
>
>
#### comment-text {#comment-text}
>
> *注释内容* → [注释内容项](#comment-text-item) [注释内容](#comment-text)<sub>可选</sub>
>
>
#### comment-text-item {#comment-text-item}
>
> *注释内容项* → 任何 Unicode 标量值,除了 U+000A 或者 U+000D
>
>
#### multiline-commnet-text {#multiline-commnet-text}
>
> *多行注释内容* → [多行注释内容项](#multiline-comment-text-item) [多行注释内容](#multiline-comment-text)<sub>可选</sub>
>
> *多行注释内容项* → [多行注释](#multiline-comment).
>
> *多行注释内容项* → [注释内容项](#comment-text-item)
>
> *多行注释内容项* → 任何 Unicode 标量值,除了 `/*` 或者 `*/`
## 标识符 {#identifiers}
*标识符identifier* 可以由以下的字符开始:大写或小写的字母 `A``Z`、下划线(`_`、基本多文种平面Basic Multilingual Plane中非字符数字组合的 Unicode 字符以及基本多文种平面以外的非个人专用区字符。在首字符之后,允许使用数字和组合 Unicode 字符。
使用保留字作为标识符,需要在其前后增加反引号(`` ` ``)。例如,`class` 不是合法的标识符,但可以使用 `` `class` ``。反引号不属于标识符的一部分,`` `x` `` 和 `x` 表示同一标识符。
闭包中如果没有明确指定参数名称,参数将被隐式命名为 `$0`、`$1`、`$2` 等等。这些命名在闭包作用域范围内是合法的标识符。
编译器给含有属性包装器呈现值的属性自动合成以美元符号(*$*)开头的标识符。你的代码可以与这些标识符进行交互,,但是不能使用该前缀声明标识符。更详细的介绍,请查看 [特性](./07_Attributes.md) 章节中的 [属性包装器](./07_Attributes.md#propertywrapper) 部分。
> 标识符语法
>
> *标识符* → [头部标识符](#identifier-head) [标识符字符组](#identifier-characters)<sub>可选</sub>
>
> *标识符* → \`[头部标识符](#identifier-head) [标识符字符组](#identifier-characters)<sub>可选</sub>\`
>
> *标识符* → [隐式参数名](#implicit-parameter-name)
>
> *标识符列表* → [标识符](#identifier) | [标识符](#identifier) **,** [标识符列表](#identifier)
>
>
#### identifier-head {#identifier-head}
>
> *头部标识符* → 大写或小写字母 A - Z
>
> *头部标识符* → **_**
>
> *头部标识符* → U+00A8U+00AAU+00ADU+00AFU+00B2U+00B5或者 U+00B7U+00BA
>
> *头部标识符* → U+00BCU+00BEU+00C0U+00D6U+00D8U+00F6或者 U+00F8U+00FF
>
> *头部标识符* → U+0100U+02FFU+0370U+167FU+1681U+180D或者 U+180FU+1DBF
>
> *头部标识符* → U+1E00U+1FFF
>
> *头部标识符* → U+200BU+200DU+202AU+202EU+203FU+2040U+2054或者 U+2060U+206F
>
> *头部标识符* → U+2070U+20CFU+2100U+218FU+2460U+24FF或者 U+2776U+2793
>
> *头部标识符* → U+2C00U+2DFF 或者 U+2E80U+2FFF
>
> *头部标识符* → U+3004U+3007U+3021U+302FU+3031U+303F或者 U+3040U+D7FF
>
> *头部标识符* → U+F900U+FD3DU+FD40U+FDCFU+FDF0U+FE1F或者 U+FE30U+FE44
>
> *头部标识符* → U+FE47U+FFFD
>
> *头部标识符* → U+10000U+1FFFDU+20000U+2FFFDU+30000U+3FFFD或者 U+40000U+4FFFD
>
> *头部标识符* → U+50000U+5FFFDU+60000U+6FFFDU+70000U+7FFFD或者 U+80000U+8FFFD
>
> *头部标识符* → U+90000U+9FFFDU+A0000U+AFFFDU+B0000U+BFFFD或者 U+C0000U+CFFFD
>
> *头部标识符* → U+D0000U+DFFFD 或者 U+E0000U+EFFFD
>
#### identifier-character {#identifier-character}
>
> *标识符字符* → 数值 0 - 9
>
> *标识符字符* → U+0300U+036FU+1DC0U+1DFFU+20D0U+20FF或者 U+FE20U+FE2F
>
> *标识符字符* → [头部标识符](#identifier-head)
>
>
#### identifier-characters {#identifier-characters}
>
> *标识符字符组* → [标识符字符](#identifier-character) [标识符字符组](#identifier-characters)<sub>可选</sub>
>
>
#### implicit-parameter-name {#implicit-parameter-name}
>
> *隐式参数名* → **$** [十进制数字列表](#decimal-digit)
>
#### property-wrapper-projection {#property-wrapper-projection}
>
> *属性包装器呈现值* → **$** [标识符字符组](#identifier-characters)
>
## 关键字和标点符号 {#keywords-and-punctuation}
下面这些被保留的关键字不允许用作标识符,除非使用反引号转义,具体描述请参考 [标识符](#identifiers)。除了 `inout``var` 以及 `let` 之外的关键字可以用作某个函数声明或者函数调用当中的外部参数名,无需添加反引号转义。当一个成员与一个关键字具有相同的名称时,不需要使用反引号来转义对该成员的引用,除非在引用该成员和使用该关键字之间存在歧义 - 例如,`self``Type``Protocol` 在显式的成员表达式中具有特殊的含义,因此它们必须在该上下文中使用反引号进行转义。
* 用在声明中的关键字:`associatedtype``class``deinit``enum``extension``fileprivate ``func``import``init``inout``internal``let``open``operator``private``protocol``public``rethrows``static``struct``subscript``typealias` 以及 `var`
* 用在语句中的关键字:`break``case``continue``default``defer``do``else``fallthrough``for``guard``if``in``repeat``return``switch``where` 以及 `while`
* 用在表达式和类型中的关键字:`as``Any``catch``false``is``nil``super``self``Self``throw``throws``true` 以及 `try `
* 用在模式中的关键字:`_`
* 以井字号(`#`)开头的关键字:`#available``#colorLiteral``#column``#else``#elseif``#endif``#error``#file``#filePath``#fileLiteral``#function``#if``#imageLiteral``#line``#selector``#sourceLocation`以及 `#warning`
* 特定上下文中被保留的关键字:`associativity``convenience``dynamic``didSet``final``get``infix``indirect``lazy``left``mutating``none``nonmutating``optional``override``postfix``precedence``prefix``Protocol``required``right``set``Type``unowned``weak` 以及 `willSet`。这些关键字在特定上下文之外可以被用做标识符。
以下符号被保留为标点符号,不能用于自定义运算符:`(``)``{``}``[``]``.``,``:``;``=``@``#``&`(作为前缀运算符)、`->`、`` ` ``、`?`、以及 `!`(作为后缀运算符)。
## 字面量 {#literal}
*字面量literal* 用来表示源码中某种特定类型的值,比如一个数字或字符串。
下面是字面量的一些示例:
```swift
42 // 整数字面量
3.14159 // 浮点数字面量
"Hello, world!" // 字符串字面量
true // 布尔值字面量
```
字面量本身并不包含类型信息。事实上,一个字面量会被解析为拥有无限的精度,然后 Swift 的类型推导会尝试去推导出这个字面量的类型。比如,在 `let x: Int8 = 42` 这个声明中Swift 使用了显式类型注解(`: Int8`)来推导出 `42` 这个整数字面量的类型是 `Int8`。如果没有可用的类型信息Swift 则会从标准库中定义的字面量类型中推导出一个默认的类型。整数字面量的默认类型是 `Int`,浮点数字面量的默认类型是 `Double`,字符串字面量的默认类型是 `String`,布尔值字面量的默认类型是 `Bool`。比如,在 `let str = "Hello, world"` 这个声明中,字符串 `"Hello, world"` 的默认推导类型就是 `String`。
当为一个字面量值指定了类型注解的时候,这个注解类型必须能通过这个字面量值实例化。也就是说,这个类型必须符合这些 Swift 标准库协议中的一个:整数字面量的 `ExpressibleByIntegerLiteral` 协议、浮点数字面量的 `ExpressibleByFloatLiteral` 协议、字符串字面量的 `ExpressibleByStringLiteral` 协议、布尔值字面量的 `ExpressibleByBooleanLiteral` 协议、只包含单个 Unicode 标量字符串文本的 `ExpressibleByUnicodeScalarLiteral` 协议以及只包含单个扩展字形簇grapheme cluster字符串文字的 `ExpressibleByExtendedGraphemeClusterLiteral` 协议。比如,`Int8` 符合 `ExpressibleByIntegerLiteral` 协议,因此它能在 `let x: Int8 = 42` 这个声明中作为整数字面量 `42` 的类型注解。
> 字面量语法
>
> *字面量* → [数值字面量](#integer-literal) | [字符串字面量](#string-literal) | [布尔值字面量](#integer-literal) | [nil 字面量](#integer-literal)
>
> *数值字面量* → **-**<sub>可选</sub> [整数字面量](#integer-literal) | **-**<sub>可选</sub> [浮点数字面量](#floating-point-literal)
>
> *布尔值字面量* → **true** | **false**
>
> *nil 字面量* → **nil**
### 整数字面量{#integer-literal}
*整数字面量Integer Literals* 表示未指定精度的整数值。整数字面量默认用十进制表示;可以加前缀来指定其他的进制。二进制字面量加 `0b`,八进制字面量加 `0o`,十六进制字面量加 `0x`。
十进制字面量包含数字 `0` 至 `9`。二进制字面量包含 `0` 和 `1`,八进制字面量包含数字 `0` 至 `7`,十六进制字面量包含数字 `0` 至 `9` 以及字母 `A` 至 `F`(大小写均可)。
负整数字面量的表示方式为在整数字面量前加负号 `-`,比如 `-42`。
整型字面面可以使用下划线(`_`)来增加数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,这同样也会被系统所忽略,并不会影响字面量的值。
除非特别指定,整数字面量的默认推导类型为 Swift 标准库类型中的 `Int`。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 [整数](../02_language_guide/01_The_Basics.md#integers)。
> 整数字面量语法
>
>
#### integer-literal {#integer-literal}
>
> *整数字面量* → [二进制字面量](#binary-literal)
>
> *整数字面量* → [八进制字面量](#octal-literal)
>
> *整数字面量* → [十进制字面量](#decimal-literal)
>
> *整数字面量* → [十六进制字面量](#hexadecimal-literal)
>
>
#### binary-literal {#binary-literal}
>
> *二进制字面量* → **0b** [二进制数字](#binary-digit) [二进制字面量字符组](#binary-literal-characters)<sub>可选</sub>
>
>
#### binary-digit {#binary-digit}
>
> *二进制数字* → 数值 0 或 1
>
> *二进制字面量字符* → [二进制数字](#binary-digit) | **_**
>
>
#### binary-literal-characters {#binary-literal-characters}
>
> *二进制字面量字符组* → [二进制字面量字符](#binary-literal-character) [二进制字面量字符组](#binary-literal-characters)<sub>可选</sub>
>
>
#### octal-literal {#octal-literal}
>
> *八进制字面量* → **0o** [八进字数字](#octal-digit) [八进制字符组](#octal-literal-characters)<sub>可选</sub>
>
>
#### octal-digit {#octal-digit}
>
> *八进字数字* → 数值 0 到 7
>
> *八进制字符* → [八进字数字](#octal-digit) | **_**
>
>
#### octal-literal-characters {#octal-literal-characters}
>
> *八进制字符组* → [八进制字符](#octal-literal-character) [八进制字符组](#octal-literal-characters)<sub>可选</sub>
>
>
#### decimal-literal {#decimal-literal}
>
> *十进制字面量* → [十进制数字](#decimal-digit) [十进制字符组](#decimal-literal-characters)<sub>可选</sub>
>
>
#### decimal-digit {#decimal-digit}
>
> *十进制数字* → 数值 0 到 9
>
>
#### decimal-literal-characters {#decimal-literal-characters}
>
> *十进制数字组* → [十进制数字](#decimal-digit) [十进制数字组](#decimal-literal-characters)<sub>可选</sub>
>
> *十进制字符* → [十进制数字](#decimal-digit) | **_**
>
> *十进制字符组* → [十进制字符](#decimal-literal-characters) [十进制字符组](#decimal-literal-characters)<sub>可选</sub>
>
>
#### hexadecimal-literal {#hexadecimal-literal}
>
> *十六进制字面量* → **0x** [十六进制数字](#hexadecimal-digit) [十六进制字面量字符组](#hexadecimal-literal-characters)<sub>可选</sub>
>
>
#### hexadecimal-digit {#hexadecimal-digit}
>
> *十六进制数字* → 数值 0 到 9, 字母 a 到 f, 或 A 到 F
>
> *十六进制字符* → [十六进制数字](#hexadecimal-digit) | **-**
>
>
#### hexadecimal-literal-characters {#hexadecimal-literal-characters}
>
> *十六进制字面量字符组* → [十六进制字符](#hexadecimal-literal-characters) [十六进制字面量字符组](#hexadecimal-literal-characters)<sub>可选</sub>
### 浮点数字面量{#floating-point-literal}
*浮点数字面量Floating-point literals*表示未指定精度浮点数的值。
浮点数字面量默认用十进制表示(无前缀),也可以用十六进制表示(加前缀 `0x`)。
十进制浮点数字面量由十进制数字串后跟十进制小数部分或十进制指数部分(或两者皆有)组成。十进制小数部分由小数点(`.`)后跟十进制数字串组成。指数部分由大写或小写字母 `e` 为前缀后跟十进制数字串组成,这串数字表示 `e` 之前的数值乘以 10 的几次方。例如:`1.25e2` 表示 1.25 x 10²也就是 `125.0`。同样,`1.25e2` 表示 1.25 x 10¯²也就是 `0.0125`。
十六进制浮点数字面量由前缀 `0x` 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字串组成。指数部分由大写或小写字母 `p` 为前缀后跟十进制数字串组成,这串数字表示 `p` 之前的数量乘以 2 的几次方。例如:`0xFp2` 表示 15 x 2²也就是 `60`。同样,`0xFp-2` 表示 15 x 2¯²也就是 `3.75`。
负数的浮点数字面量由负号(`-`)和浮点数字面量组成,例如 `-42.5`。
浮点数字面量允许使用下划线(`_`)来增强数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,并不会影响字面量的值。
除非特别指定,浮点数字面量的默认推导类型为 Swift 标准库类型中的 `Double`,表示 64 位浮点数。Swift 标准库也定义了 `Float` 类型,表示 32 位浮点数。
> 浮点数字面量语法
>
>
#### floating-point-literal {#floating-point-literal}
>
> *浮点数字面量* → [十进制字面量](#decimal-literal) [十进制分数](#decimal-fraction)<sub>可选</sub> [十进制指数](#decimal-exponent)<sub>可选</sub>
>
> *浮点数字面量* → [十六进制字面量](#hexadecimal-literal) [十六进制分数](#hexadecimal-fraction)<sub>可选</sub> [十六进制指数](#hexadecimal-exponent)
>
>
#### decimal-fraction {#decimal-fraction}
>
> *十进制分数* → **.** [十进制字面量](#decimal-literal)
>
>
#### decimal-exponent {#decimal-exponent}
>
> *十进制指数* → [十进制指数 e](#floating-point-e) [正负号](#sign)<sub>可选</sub> [十进制字面量](#decimal-literal)
>
>
#### hexadecimal-fraction {#hexadecimal-fraction}
>
> *十六进制分数* → **.** [十六进制数字](#hexadecimal-digit) [十六进制字面量字符组](#hexadecimal-literal-characters)<sub>可选</sub>
>
>
#### hexadecimal-exponent {#hexadecimal-exponent}
>
> *十六进制指数* → [十六进制指数 p](#floating-point-p) [正负号](#sign)<sub>可选</sub> [十进制字面量](#decimal-literal)
>
>
#### floating-point-e {#floating-point-e}
>
> *十进制指数 e* → **e** | **E**
>
>
#### floating-point-p {#floating-point-p}
>
> *十六进制指数 p* → **p** | **P**
>
>
#### sign {#sign}
>
> *正负号* → **+** | **-**
### 字符串字面量 {#string-literal}
字符串字面量是被引号包括的一串字符组成。单行字符串字面量是被包在双引号中的一串字符组成,形式如下:
> "`字符`"
字符串字面量中不能包含未转义的双引号(`"`)、未转义的反斜线(`\`)、回车符、换行符。
多行字符串字面量被包在三个双引号中的一串字符组成,形式如下:
> """
> `字符`
> """
与单行字符串字面量不同的是,多行字符串字面量可以包含不转义的双引号("),回车以及换行。它不能包含三个未转义的连续双引号。
`"""` 之后的回车或者换行开始多行字符串字面量,它们不是字符串的一部分。结束部分的 `"""` 以及它之前的回车或者换行,也不是字符串的一部分。要让多行字符串字面量的开始或结束带有换行,就在第一行或者最后一行写一个空行。
多行字符串字面量可以使用任何空格或制表符组合进行缩进;这些缩进不会包含在字符串中。`"""` 的结束符号决定了缩进:字面量中的每一个非空行开头都必须与结束符 `"""` 之前出现的缩进完全一致;空格和制表符不会被转换。你可以在缩进后包含额外的空格和制表符;这些空格和制表符会在字符串中出现。
多行字符串字面量中的一行结束使用规范化的换行符号。尽管你的源代码混用了回车和换行符,字符串中所有的行结束都必须一样.
在多行字符串字面量里,在行末用反斜线(`\`)可以省略字符串行间中断。反斜线和换行符之间的空白也将被忽略。你可以在你的代码里用这种语法硬包裹多行字符串字面量,而不改变结果字符串的值。
可以在字符串字面量中使用的转义特殊符号如下:
* 空字符 `\0`
* 反斜线 `\\`
* 水平制表符 `\t`
* 换行符 `\n`
* 回车符 `\r`
* 双引号 `\"`
* 单引号 `\'`
* Unicode 标量 `\u{`n`}`n 为一到八位的十六进制数字
字符串字面量允许在反斜杠(`\`)后的括号 `()` 中插入表达式的值。插入表达式可以包含字符串字面量,但不能包含未转义的反斜线(`\`)、回车符以及换行符。
例如,以下所有字符串字面量的值都是相同的:
```swift
"1 2 3"
"1 2 \("3")"
"1 2 \(3)"
"1 2 \(1 + 2)"
let x = 3; "1 2 \(x)"
```
由扩展分隔符包裹的字符串,它是由引号以及成对出现的数字符号(`#`)包裹的字符串序列。由扩展分隔符包裹的字符串形式如下所示:
> \#"`characters`"#
>
> \#"""
>
> `characters`
>
> """#
特殊字符在被扩展分隔符分隔的结果字符串中会展示为普通字符,而不是特殊字符。你可以使用扩展分隔符来创建一些通常情况下具有特殊效果的字符串。例如,生成字符串插值,启动转义序列或终止字符串。
以下所示,由字符串字面量和扩展分隔符所创建的字符串是等价的:
```swift
let string = #"\(x) \ " \u{2603}"#
let escaped = "\\(x) \\ \" \\u{2603}"
print(string)
// Prints "\(x) \ " \u{2603}"
print(string == escaped)
// Prints "true"
```
如果在一个字符串中使用多对扩展分隔符,请不要在分隔符之间使用空格。
```swift
print(###"Line 1\###nLine 2"###) // OK
print(# # #"Line 1\# # #nLine 2"# # #) // Error
```
使用扩展分隔符创建的多行字符串字面量与普通多行字符串字面量具有相同的缩进要求。
字符串字面量的默认推导类型为 `String`。更多有关 `String` 类型的信息请参考 [字符串和字符](../02_language_guide/03_Strings_and_Characters.md) 以及 [*字符串结构参考*](https://developer.apple.com/documentation/swift/string)。
`` 操作符连接的字符型字面量是在编译时进行连接的。比如下面的 `textA``textB` 是完全一样的,`textA` 没有任何运行时的连接操作。
```swift
let textA = "Hello " + "world"
let textB = "Hello world"
```
> 字符串字面量语法
>
> *字符串字面量* → [静态字符串字面量](#static-string-literal) | [插值字符串字面量](#interpolated-string-literal)
>
> *字符串开分隔定界符* → [字符串扩展分隔符](#extended-string-literal-delimiter) **"**
>
> *字符串闭分隔定界符* → **"** [字符串扩展分隔符](#extended-string-literal-delimiter)<sub>可选</sub>
>
>
#### static-string-literal {#static-string-literal}
>
> *静态字符串字面量* → [字符串开分隔定界符](#extended-string-literal-delimiter) [引用文本](#quoted-text)<sub>可选</sub> [字符串闭分隔定界符](#extended-string-literal-delimiter)
>
> *静态字符串字面量* → [多行字符串开分隔定界符](#extended-string-literal-delimiter) [多行引用文本](#multiline-quoted-text)<sub>可选</sub> [多行字符串闭分隔定界符](#extended-string-literal-delimiter)
>
> *多行字符串开分隔定界符* → [字符串扩展分隔符](#extended-string-literal-delimiter) **"""**
>
> *多行字符串闭分隔定界符* → **"""** [字符串扩展分隔符](#extended-string-literal-delimiter)
>
>
#### extended-string-literal-delimiter {#extended-string-literal-delimiter}
>
> *字符串扩展分隔符* → **#** [字符串扩展分隔符](#extended-string-literal-delimiter)<sub>可选</sub>
>
>
#### quoted-text {#quoted-text}
>
> *引用文本* → [引用文本项](#quoted-text-item) [引用文本](#quoted-text)<sub>可选</sub>
>
>
#### quoted-text-item {#quoted-text-item}
>
> *引用文本项* → [转义字符](#escaped-character)
>
> *引用文本项* → 除了 **"**、**\\**、U+000A、U+000D 以外的所有 Unicode 字符
>
>
#### multiline-quoted-text {#multiline-quoted-text}
>
> *多行引用文本* → [多行引用文本项](#multiline-quoted-text-item) [多行引用文本](#multiline-quoted-text)<sub>可选</sub>
>
>
#### multiline-quoted-text-item {#multiline-quoted-text-item}
>
> *多行引用文本项* [转义字符](#escaped-character)<sub>可选</sub>
>
>
#### multiline-quoted-text {#multiline-quoted-text}
>
> *多行引用文本* → 除了 **\\** 以外的任何 Unicode 标量值
>
> *多行引用文本* → [转义换行](#escaped-newline)
>
>
#### interpolated-string-literal {#interpolated-string-literal}
>
> *插值字符串字面量* → [字符串开分隔定界符](#extended-string-literal-delimiter) [插值文本](#interpolated-text)<sub>可选</sub> [字符串闭分隔定界符](#extended-string-literal-delimiter)
>
> *插值字符串字面量* → [多行字符串开分隔定界符](#extended-string-literal-delimiter) [插值文本](#interpolated-text)<sub>可选</sub> [多行字符串闭分隔定界符](#extended-string-literal-delimiter)
>
>
#### interpolated-text {#interpolated-text}
>
> *插值文本* → [插值文本项](#interpolated-text-item) [插值文本](#interpolated-text)<sub>可选</sub>
>
>
#### interpolated-text-item {#interpolated-text-item}
>
> *插值文本项* → **\\(**[ 表达式 ](./04_Expressions.md)**)** | [引用文本项](#quoted-text-item)
>
> *多行插值文本* → [多行插值文本项](#multiline-quoted-text-item) [多行插值文本](#multiline-quoted-text)<sub>可选</sub>
>
> *多行插值文本项* → **\\(** [表达式](./04_Expressions.md) **)** | [多行引用文本项](#multiline-quoted-text-item)
>
>
#### escape-sequence {#escape-sequence}
>
> *转义序列* → **\\** [字符串扩展分隔符](#extended-string-literal-delimiter)
>
>
#### escaped-character {#escaped-character}
>
> *转义字符* → [转义序列](#escape-sequence) **0** | [转义序列](#escape-sequence) **\\** | [转义序列](#escape-sequence) **t** | [转义序列](#escape-sequence) **n** | [转义序列](#escape-sequence) **r** | [转义序列](#escape-sequence) **\"** | [转义序列](#escape-sequence) **'**
>
> *转义字符* → [转义序列](#escape-sequence) **u {** [unicode 标量数字](#unicode-scalar-digits) **}**
>
>
#### unicode-scalar-digits {#unicode-scalar-digits}
>
> *unicode 标量数字* → 一到八位的十六进制数字
>
>
#### escaped-newline {#escaped-newline}
>
> *转义换行符* → [转义序列](#escape-sequence) [空白](#whitespace)<sub>可选</sub> [断行符](#line-break)
## 运算符 {#operator}
Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基础运算符](../02_language_guide/02_Basic_Operators.md) 和 [高级运算符](../02_language_guide/27_Advanced_Operators.md) 中进行了阐述。这一小节将描述哪些字符能用于自定义运算符。
自定义运算符可以由以下其中之一的 ASCII 字符 `/``=``-``+``!``*``%``<``>``&``|``^``?` 以及 `~`,或者后面语法中规定的任一个 Unicode 字符(其中包含了*数学运算符*、*零散符号Miscellaneous Symbols* 以及*印刷符号Dingbats*之类的 Unicode 块)开始。在第一个字符之后,允许使用组合型 Unicode 字符。
您也可以以点号(`.`)开头来定义自定义运算符。这些运算符可以包含额外的点。例如 `.+.` 会被看作一个单独的运算符。如果某个运算符不是以点号开头的,那么它就无法再包含另外的点号了。例如,`+.+` 就会被看作为一个 `+` 运算符后面跟着一个 `.+` 运算符。
虽然您可以用问号 `?` 来自定义运算符,但是这个运算符不能只包含单独的一个问号。此外,虽然运算符可以包含一个惊叹号 `!`,但是前缀运算符不能够以问号或者惊叹号开头。
> 注意
>
> 以下这些标记 `=`、`->`、`//`、`/*`、`*/`、`.`,前缀运算符 `<`、`&` 和 `?`,中缀运算符 `?`,后缀运算符 `>`、`!` 和 `?` 是被系统保留的。这些符号不能被重载,也不能用作自定义运算符。
运算符两侧的空白被用来区分该运算符是否为前缀运算符、后缀运算符或二元运算符。规则总结如下:
* 如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:`a+++b``a +++ b` 当中的 `+++` 运算符会被看作二元运算符。
* 如果运算符只有左侧空白,将被看作一元前缀运算符。例如 `a +++b` 中的 `+++` 运算符会被看做是一元前缀运算符。
* 如果运算符只有右侧空白,将被看作一元后缀运算符。例如 `a+++ b` 中的 `+++` 运算符会被看作是一元后缀运算符。
* 如果运算符左侧没有空白并紧跟 `.`,将被看作一元后缀运算符。例如 `a+++.b` 中的 `+++` 运算符会被视为一元后缀运算符(即上式被视为 `a+++ .b` 而不是 `a +++ .b`)。
鉴于这些规则,`(``[``{` 是在运算符前面,`)``]``}` 是在运算符后面,以及字符 `,``;``:` 都被视为空白。
以上规则需注意一点。如果预定义运算符 `!``?` 左侧没有空白,则不管右侧是否有空白都将被看作后缀运算符。如果将 `?` 用作可选链式调用运算符,左侧必须无空白。如果用于条件运算符 `? :`,必须两侧都有空白。
在某些特定的设计中,以 `<``>` 开头的运算符会被分离成两个或多个符号。剩余部分可能会以同样的方式被再次分离。因此,在 `Dictionary<String, Array<Int>>` 中没有必要添加空白来消除闭合字符 `>` 的歧义。在这个例子中,闭合字符 `>` 不会被视为单独的符号,因而不会被错误解析为 `>>` 运算符。
要学习如何自定义运算符,请参考 [自定义运算符](../02_language_guide/27_Advanced_Operators.md#custom-operators) 和 [运算符声明](./06_Declarations.md#operator-declaration)。要学习如何重载运算符,请参考 [运算符函数](../02_language_guide/27_Advanced_Operators.md#operator-functions)。
> 运算符语法
>
> *运算符* → [头部运算符](#operator-head) [运算符字符组](#operator-characters)<sub>可选</sub>
>
> *运算符* → [头部点运算符](#dot-operator-head) [点运算符字符组](#dot-operator-characters)
>
>
#### operator-head {#operator-head}
>
> *头部运算符* → **/** | **=** | **-** | **+** | **!** | __*__ | **%** | **<** | **>** | **&** | **|** | **^** | **~** | **?**
>
> *头部运算符* → U+00A1U+00A7
>
> *头部运算符* → U+00A9 或 U+00AB
>
> *头部运算符* → U+00AC 或 U+00AE
>
> *头部运算符* → U+00B0U+00B1
>
> *头部运算符* → U+00B6U+00BBU+00BFU+00D7或 U+00F7
>
> *头部运算符* → U+2016U+2017
>
> *头部运算符* → U+2020U+2027
>
> *头部运算符* → U+2030U+203E
>
> *头部运算符* → U+2041U+2053
>
> *头部运算符* → U+2055U+205E
>
> *头部运算符* → U+2190U+23FF
>
> *头部运算符* → U+2500U+2775
>
> *头部运算符* → U+2794U+2BFF
>
> *头部运算符* → U+2E00U+2E7F
>
> *头部运算符* → U+3001U+3003
>
> *头部运算符* → U+3008U+3020
>
> *头部运算符* → U+3030
>
>
#### operator-character {#operator-character}
>
> *运算符字符* → [头部运算符](#operator-head)
>
> *运算符字符* → U+0300U+036F
>
> *运算符字符* → U+1DC0U+1DFF
>
> *运算符字符* → U+20D0U+20FF
>
> *运算符字符* → U+FE00U+FE0F
>
> *运算符字符* → U+FE20U+FE2F
>
> *运算符字符* → U+E0100U+E01EF
>
>
#### operator-characters {#operator-characters}
>
> *运算符字符组* → [运算符字符](#operator-character) [运算符字符组](#operator-characters)<sub>可选</sub>
>
>
#### dot-operator-head {#dot-operator-head}
>
> *头部点运算符* → **.**
>
>
#### dot-operator-character {#dot-operator-character}
>
> *点运算符字符* → **.** | [运算符字符](#operator-character)
>
>
#### dot-operator-characters {#dot-operator-characters}
>
> *点运算符字符组* → [点运算符字符](#dot-operator-character) [点运算符字符组](#dot-operator-characters)<sub>可选</sub>
>
> *二元运算符* → [运算符](#operator)
>
> *前缀运算符* → [运算符](#operator)
>
> *后缀运算符* → [运算符](#operator)

View File

@ -2,7 +2,7 @@
Swift 语言存在两种类型:命名型类型和复合型类型。*命名型类型*是指定义时可以给定名字的类型。命名型类型包括类、结构体、枚举和协议。比如,一个用户定义类 `MyClass` 的实例拥有类型 `MyClass`。除了用户定义的命名型类型Swift 标准库也定义了很多常用的命名型类型,包括那些表示数组、字典和可选值的类型。
那些通常被其它语言认为是基本或原始的数据型类型,比如表示数字、字符和字符串的类型,实际上就是命名型类型,这些类型在 Swift 标准库中是使用结构体来定义和实现的。因为它们是命名型类型,因此你可以按照 [扩展](../chapter2/20_Extensions.md) 和 [扩展声明](./06_Declarations.md#extension_declaration) 中讨论的那样,声明一个扩展来增加它们的行为以满足你程序的需求。
那些通常被其它语言认为是基本或原始的数据型类型,比如表示数字、字符和字符串的类型,实际上就是命名型类型,这些类型在 Swift 标准库中是使用结构体来定义和实现的。因为它们是命名型类型,因此你可以按照 [扩展](../02_language_guide/20_Extensions.md) 和 [扩展声明](./06_Declarations.md#extension-declaration) 中讨论的那样,声明一个扩展来增加它们的行为以满足你程序的需求。
*复合型类型*是没有名字的类型,它由 Swift 本身定义。Swift 存在两种复合型类型:函数类型和元组类型。一个复合型类型可以包含命名型类型和其它复合型类型。例如,元组类型 `(Int, (Int, Int))` 包含两个元素:第一个是命名型类型 `Int`,第二个是另一个复合型类型 `(Int, Int)`
@ -41,14 +41,14 @@ Swift 语言存在两种类型:命名型类型和复合型类型。*命名型
> *类型***** [类型](#type) ****
## 类型注解 {#type-annotation-h}
*类型注解*显式地指定一个变量或表达式的类型。类型注解始于冒号 `:` 终于类型,比如下面两个例子:
*类型注解*显式地指定一个变量或表达式的类型。类型注解冒号 `:`)开始, 以类型结尾,比如下面两个例子:
```swift
let someTuple: (Double, Double) = (3.14159, 2.71828)
func someFunction(a: Int) { /* ... */ }
```
在第一个例子中,表达式 `someTuple` 的类型被指定为 `(Double, Double)`。在第二个例子中,函数 `someFunction` 的参 `a` 的类型被指定为 `Int`
在第一个例子中,表达式 `someTuple` 的类型被指定为 `(Double, Double)`。在第二个例子中,函数 `someFunction``a` 的类型被指定为 `Int`
类型注解可以在类型之前包含一个类型特性的可选列表。
@ -56,10 +56,10 @@ func someFunction(a: Int) { /* ... */ }
>
#### type-annotation {#type-annotation}
> *类型注解***:** [*特性列表*](./07_Attributes.md#attributes)<sub>可选</sub> **输入输出参数**<sub>可选</sub> [*类型*](#type)
> *类型注解***:** [特性列表](./07_Attributes.md#attributes)<sub>可选</sub> **输入输出参数**<sub>可选</sub> [类型](#type)
## 类型标识符 {#type-identifier-h}
*类型标识符*引用命名型类型,还可引用命名型或复合型类型的别名。
*类型标识符*可以引用命名型类型,还可引用命名型或复合型类型的别名。
大多数情况下,类型标识符引用的是与之同名的命名型类型。例如类型标识符 `Int` 引用命名型类型 `Int`,同样,类型标识符 `Dictionary<String, Int>` 引用命名型类型 `Dictionary<String, Int>`
@ -80,16 +80,15 @@ var someValue: ExampleModule.MyType
>
#### type-identifier {#type-identifier}
> *类型标识符* → [*类型名称*](#type-name) [*泛型参子句*](./09_Generic_Parameters_and_Arguments.md#generic_argument_clause)<sub>可选</sub> | [*类型名称*](#type-name) [*泛型参子句*](./09_Generic_Parameters_and_Arguments.md#generic_argument_clause)<sub>可选</sub> **.** [*类型标识符*](#type-identifier)
>
> *类型标识符* → [类型名称](#type-name) [泛型参子句](./09_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub> | [类型名称](#type-name) [泛型参子句](./09_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub> **.** [类型标识符](#type-identifier)
#### type-name {#type-name}
> *类型名称* → [*标识符*](./02_Lexical_Structure.md#identifier)
> *类型名称* → [标识符](./02_Lexical_Structure.md#identifier)
## 元组类型 {#tuple-type-h}
*元组类型*是使用括号括起来的零个或多个类型,类型间用逗号隔开。
你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号 `(:)` 组成。[函数和多返回值](../chapter2/06_Functions.md#functions_with_multiple_return_values) 章节里有一个展示上述特性的例子。
你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号 `(:)` 组成。[函数和多返回值](../02_language_guide/06_Functions.md#functions-with-multiple-return-values) 章节里有一个展示上述特性的例子。
当一个元组类型的元素有名字的时候,这个名字就是类型的一部分。
@ -106,37 +105,37 @@ someTuple = (left: 5, right: 5) // 错误:命名类型不匹配
>
#### tuple-type {#tuple-type}
> *元组类型***(** **)** | **(** [*元组类型元素*](#tuple-type-element) **,** [*元组类型元素列表*](#tuple-type-element-list) **)**
> *元组类型***(** **)** | **(** [元组类型元素](#tuple-type-element) **,** [元组类型元素列表](#tuple-type-element-list) **)**
>
#### tuple-type-element-list {#tuple-type-element-list}
> *元组类型元素列表* → [*元组类型元素*](#tuple-type-element) | [*元组类型元素*](#tuple-type-element) **,** [*元组类型元素列表*](#tuple-type-element-list)
> *元组类型元素列表* → [元组类型元素](#tuple-type-element) | [元组类型元素](#tuple-type-element) **,** [元组类型元素列表](#tuple-type-element-list)
>
#### tuple-type-element {#tuple-type-element}
> *元组类型元素* → [*元素名*](#element-name) [*类型注解*](#type-annotation) | [*类型*](#type)
> *元组类型元素* → [元素名](#element-name) [类型注解](#type-annotation) | [类型](#type)
>
#### element-name {#element-name}
> *元素名* → [*标识符*](./02_Lexical_Structure.md#identifier)
> *元素名* → [标识符](./02_Lexical_Structure.md#identifier)
>
## 函数类型 {#function-type-h}
*函数类型*表示一个函数、方法或闭包的类型,它由参类型和返回值类型组成,中间用箭头(`->`)隔开:
*函数类型*表示一个函数、方法或闭包的类型,它由参类型和返回值类型组成,中间用箭头(`->`)隔开:
> `参类型`->`返回值类型`
> `参类型`->`返回值类型`
*参类型*是由逗号间隔的类型列表。由于*返回值类型*可以是元组类型,所以函数类型支持多返回值的函数与方法。
*参类型*是由逗号间隔的类型列表。由于*返回值类型*可以是元组类型,所以函数类型支持多返回值的函数与方法。
你可以对参类型为 `() -> T`(其中 T 是任何类型)的函数使用 `autoclosure` 特性这会自动将参数表达式转化为闭包,表达式的结果即闭包返回值。这从语法结构上提供了一种便捷:延迟对表达式的求值,直到其值在函数体中被调用。以自动闭包做为参的函数类型的例子详见 [自动闭包](../chapter2/07_Closures.md#autoclosures)。
你可以对参类型为 `() -> T`(其中 T 是任何类型)的函数使用 `autoclosure` 特性这会在调用侧隐式创建一个闭包。这从语法结构上提供了一种便捷:延迟对表达式的求值,直到其值在函数体中被调用。以自动闭包做为参的函数类型的例子详见 [自动闭包](../02_language_guide/07_Closures.md#autoclosures)。
函数类型可以拥有一个可变参数作为*参数类型*中的最后一个参数。从语法角度上讲,可变参数由一个基础类型名字紧随三个点(`...`)组成,如 `Int...`。可变参数被认为是一个包含了基础类型元素的数组。即 `Int...` 就是 `[Int]`。关于使用可变参数的例子,请参阅 [可变参数](../chapter2/06_Functions.md#variadic_parameters)。
函数类型可以拥有一个可变参数在*形参类型*中。从语法角度上讲,可变参数由一个基础类型名字紧随三个点(`...`)组成,如 `Int...`。可变参数被认为是一个包含了基础类型元素的数组。即 `Int...` 就是 `[Int]`。关于使用可变参数的例子,请参阅 [可变参数](../02_language_guide/06_Functions.md#variadic-parameters)。
为了指定一个 `in-out` 参数,可以在参类型前加 `inout` 前缀。但是你不可以对可变参数或返回值类型使用 `inout`。关于这种参的详细讲解请参阅 [输入输出参数](../chapter2/06_Functions.md#in_out_parameters)。
为了指定一个 `in-out` 参数,可以在参类型前加 `inout` 前缀。但是你不可以对可变参数或返回值类型使用 `inout`。关于这种参的详细讲解请参阅 [输入输出参数](../02_language_guide/06_Functions.md#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``(()) -> ()` 是一样的 - 一个将空元组作为唯一参的函数。但这些类型和 `() -> ()` 是不一样的 - 一个无实参的函数
函数和方法中的变量名并不是函数类型的一部分。例如:
函数和方法中的实参名并不是函数类型的一部分。例如:
```swift
func someFunction(left: Int, right: Int) {}
@ -155,7 +154,7 @@ func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {}
f = functionWithDifferentNumberOfArguments // 错误
```
由于变量标签不是函数类型的一部分,你可以在写函数类型的时候省略它们。
由于实参标签不是函数类型的一部分,你可以在写函数类型的时候省略它们。
```swift
var operation: (lhs: Int, rhs: Int) -> Int // 错误
@ -163,14 +162,14 @@ var operation: (_ lhs: Int, _ rhs: Int) -> Int // 正确
var operation: (Int, Int) -> Int // 正确
```
如果一个函数类型包涵多个箭头(->),那么函数类型将从右向左进行组合。例如,函数类型 `(Int) -> (Int) -> Int` 可以理解为 `(Int) -> ((Int) -> Int)`,也就是说,该函数类型的参数为 `Int` 类型,其返回类型是一个参数类型为 `Int`,返回类型为 `Int` 的函数。
如果一个函数类型包涵多个箭头(->),那么函数类型将从右向左进行组合。例如,函数类型 `(Int) -> (Int) -> Int` 可以理解为 `(Int) -> ((Int) -> Int)`,也就是说,该函数传入 `Int`,并返回另一个传入并返回 `Int` 的函数。
函数类型若要抛出错误就必须使用 `throws` 关键字来标记,若要重抛错误必须使用 `rethrows` 关键字来标记。`throws` 关键字是函数类型的一部分,非抛出函数是抛出函数函数的一个子类型。因此,在使用抛出函数的地方也可以使用不抛出函数。抛出和重抛函数的相关描述见章节 [抛出函数与方法](./06_Declarations.md#throwing_functions_and_methods) 和 [重抛函数与方法](./06_Declarations.md#rethrowing_functions_and_methods)。
函数类型若要抛出重抛错误必须使用 `throws` 关键字来标记。`throws` 关键字是函数类型的一部分,非抛出函数是抛出函数子类型。因此,在使用抛出函数的地方也可以使用不抛出函数。抛出和重抛函数的相关描述见章节 [抛出函数与方法](./06_Declarations.md#throwing-functions-and-methods) 和 [重抛函数与方法](./06_Declarations.md#rethrowing-functions-and-methods)。
### 对非逃逸闭包的限制 {#Restrictions for Nonescaping Closures}
当非逃逸闭包函数是参时,不能存储在属性、变量或任何 `Any` 类型的常量中,因为这可能导致值的逃逸。
当非逃逸闭包函数是参时,不能存储在属性、变量或任何 `Any` 类型的常量中,因为这可能导致值的逃逸。
当非逃逸闭包函数是参时,不能作为参传递到另一个非逃逸闭包函数中。这样的限制可以让 Swift 在编译时就完成更的内存访问冲突检查,而不是在运行时。举个例子:
当非逃逸闭包函数是参时,不能作为参传递到另一个非逃逸闭包函数中。这样的限制可以让 Swift 在编译时就完成更的内存访问冲突检查,而不是在运行时。举个例子:
```swift
let external: (Any) -> Void = { _ in () }
@ -186,37 +185,31 @@ func takesTwoFunctions(first: (Any) -> Void, second: (Any) -> Void) {
}
```
在上面代码里,`takesTwoFunctions(first:second:)` 的两个参都是函数。它们都没有标记为 `@escaping`, 因此它们都是非逃逸的。
在上面代码里,`takesTwoFunctions(first:second:)` 的两个参都是函数。它们都没有标记为 `@escaping`, 因此它们都是非逃逸的。
上述例子里的被标记为“错误”的四个函数调用会产生编译错误。因为参 `first``second` 是非逃逸函数,它们不能够作为参被传递到另一个非闭包函数。相对的, 标记“正确”的两个函数不会产生编译错误。这些函数调用不会违反限制,因为 `external` 不是 `takesTwoFunctions(first:second:)` 的参之一。
上述例子里的被标记为“错误”的四个函数调用会产生编译错误。因为`first``second` 是非逃逸函数,它们不能够作为参被传递到另一个非闭包函数。相对的, 标记“正确”的两个函数不会产生编译错误。这些函数调用不会违反限制,因为 `external` 不是 `takesTwoFunctions(first:second:)`参之一。
如果你需要避免这个限制,标记其中之一的参数为逃逸,或者使用 `withoutActuallyEscaping(_:do:)` 函数临时转换非逃逸函数的其中一个参数为逃逸函数。关于避免内存访问冲突,可以参阅 [内存安全](../chapter2/24_Memory_Safety.md)。
如果你需要避免这个限制,标记其中一个形参为逃逸,或者使用 `withoutActuallyEscaping(_:do:)` 函数临时转换其中一个非逃逸函数形参为逃逸函数。关于避免内存访问冲突,可以参阅 [内存安全](../02_language_guide/25_Memory_Safety.md)。
> 函数类型语法
>
#### function-type {#function-type}
> *函数类型* → [*特性列表*](./07_Attributes.md#attributes)<sub>可选</sub> [*函数类型子句*](#function-type-argument-clause) **throws**<sub>可选</sub> **->** [*类型*](#type)
>
> *函数类型* → [*特性列表*](./07_Attributes.md#attributes)<sub>可选</sub> [*函数类型子句*](#function-type-argument-clause) **rethrows­** **->** [*类型*](#type)
>
> *函数类型* → [特性列表](./07_Attributes.md#attributes)<sub>可选</sub> [函数类型子句](#function-type-argument-clause) **throws**<sub>可选</sub> **->** [类型](#type)
#### function-type-argument-clause {#function-type-argument-clause}
> *函数类型子句***(**­ **)**­
> *函数类型子句***(** [*函数类型参列表*](#function-type-argument-list) *...*­ <sub>可选</sub> **)**
>
> *函数类型子句***(** [函数类型参列表](#function-type-argument-list) *...*­ <sub>可选</sub> **)**
#### function-type-argument-list {#function-type-argument-list}
> *函数类型参列表* → [*函数类型参数*](function-type-argument) | [*函数类型参数*](function-type-argument) [*函数类型参列表*](#function-type-argument-list)
>
> *函数类型参列表* → [函数类型](#function-type-argument) | [函数类型](#function-type-argument) [函数类型参列表](#function-type-argument-list)
#### function-type-argument {#function-type-argument}
> *函数类型参数* → [*特性列表*](./07_Attributes.md#attributes)<sub>可选</sub> **输入输出参数**<sub>可选</sub> [*类型*](#type) | [*参数标签*](#argument-label) [*类型注解*](#type-annotation)
>
> *函数类型实参* → [特性列表](./07_Attributes.md#attributes)<sub>可选</sub> **输入输出参数**<sub>可选</sub> [类型](#type) | [实参标签](#argument-label) [类型注解](#type-annotation)
#### argument-label {#argument-label}
> *参标签* → [*标识符*](./02_Lexical_Structure.md#identifier)
>
> *参标签* → [标识符](./02_Lexical_Structure.md#identifier)
## 数组类型 {#array-type-h}
Swift 语言为标准库中定义的 `Array<Element>` 类型提供了如下语法糖:
@ -241,13 +234,13 @@ var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
访问一个多维数组的元素时,最左边的下标指向最外层数组的相应位置元素。接下来往右的下标指向第一层嵌入的相应位置元素,依次类推。这就意味着,在上面的例子中,`array3D[0]``[[1, 2], [3, 4]]``array3D[0][1]``[3, 4]``array3D[0][1][1]` 则是 `4`
关于 Swift 标准库中 `Array` 类型的详细讨论,请参阅 [数组](../chapter2/04_Collection_Types.md#arrays)。
关于 Swift 标准库中 `Array` 类型的详细讨论,请参阅 [数组](../02_language_guide/04_Collection_Types.md#arrays)。
> 数组类型语法
>
#### array-type {#array-type}
> *数组类型***[** [*类型*](#type) **]**
> *数组类型***[** [类型](#type) **]**
>
## 字典类型 {#dictionary-type-h}
@ -269,13 +262,13 @@ let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]
字典中键的类型必须符合 Swift 标准库中的 `Hashable` 协议。
关于 Swift 标准库中 `Dictionary` 类型的详细讨论,请参阅 [字典](../chapter2/04_Collection_Types.md#dictionaries)。
关于 Swift 标准库中 `Dictionary` 类型的详细讨论,请参阅 [字典](../02_language_guide/04_Collection_Types.md#dictionaries)。
> 字典类型语法
>
#### dictionary-type {#dictionary-type}
> *字典类型***[** [*类型*](#type) **:** [*类型*](#type) **]**
> *字典类型***[** [类型](#type) **:** [类型](#type) **]**
>
## 可选类型 {#optional-type-h}
@ -299,15 +292,15 @@ optionalInteger! // 42
使用 `!` 运算符解包值为 `nil` 的可选值会导致运行错误。
你也可以使用可选链式调用和可选绑定来选择性在可选表达式上执行操作。如果值为 `nil`,不会执行任何操作,因此也就没有运行错误产生。
你也可以使用可选链式调用和可选绑定来选择性在可选表达式上执行操作。如果值为 `nil`,不会执行任何操作,因此也就没有运行错误产生。
更多细节以及更多如何使用可选类型的例子,请参阅 [可选类型](../chapter2/01_The_Basics.md#optionals)。
更多细节以及更多如何使用可选类型的例子,请参阅 [可选类型](../02_language_guide/01_The_Basics.md#optionals)。
> 可选类型语法
>
#### optional-type {#optional-type}
> *可选类型* → [*类型*](#type) **?**
> *可选类型* → [类型](#type) **?**
>
## 隐式解析可选类型 {#implicitly-unwrapped-optional-type-h}
@ -336,23 +329,23 @@ let implicitlyUnwrappedArray: [Int]! // 正确
可以使用可选链式调用对隐式解析可选表达式选择性地执行操作。如果值为 `nil`,就不会执行任何操作,因此也不会产生运行错误。
关于隐式解析可选类型的更多细节,请参阅 [隐式解析可选类型](../chapter2/01_The_Basics.md#implicityly_unwrapped_optionals)。
关于隐式解析可选类型的更多细节,请参阅 [隐式解析可选类型](../02_language_guide/01_The_Basics.md#implicityly-unwrapped-optionals)。
> 隐式解析可选类型语法
>
#### implicitly-unwrapped-optional-type {#implicitly-unwrapped-optional-type}
> *隐式解析可选类型* → [*类型*](#type) **!**
> *隐式解析可选类型* → [类型](#type) **!**
>
## 协议合成类型 {#protocol-composition-type-h}
*协议合成类型*定义了一种遵循协议列表中每个指定协议的类型,或者一个现有类型的子类并遵循协议列表中每个指定协议。协议合成类型只能用在类型注解、泛型参子句和泛型 `where` 子句中指定类型。
*协议合成类型*定义了一种遵循协议列表中每个指定协议的类型,或者一个现有类型的子类并遵循协议列表中每个指定协议。协议合成类型只能用在类型注解、泛型参子句和泛型 `where` 子句中指定类型。
协议合成类型的形式如下:
> `Protocol 1` & `Procotol 2`
协议合成类型允许你指定一个值,其类型遵循多个协议的要求而不需要定义一个新的命名型协议来继承它想要符合的各个协议。比如,协议合成类型 `Protocol A & Protocol B & Protocol C` 等效于一个从 `Protocol A``Protocol B``Protocol C` 继承而来的新协议。同样的,你可以使用 `SuperClass & ProtocolA` 来取代明一个新的协议作为 `SuperClass` 的子类并遵循 `ProtocolA`
协议合成类型允许你指定一个值,其类型遵循多个协议的要求而不需要定义一个新的命名型协议来继承它想要符合的各个协议。比如,协议合成类型 `Protocol A & Protocol B & Protocol C` 等效于一个从 `Protocol A``Protocol B``Protocol C` 继承而来的新协议。同样的,你可以使用 `SuperClass & ProtocolA` 来取代明一个新的协议作为 `SuperClass` 的子类并遵循 `ProtocolA`
协议合成列表中的每一项都必须是下面所列情况之一,列表中最多只能包含一个类:
@ -371,11 +364,11 @@ typealias PQR = PQ & Q & R
>
#### protocol-composition-type {#protocol-composition-type}
> *协议合成类型* → [*协议标识符*](#protocol-identifier) & [*协议合成延续*](#protocol-composition-continuation)
> *协议合成类型* → [协议标识符](#protocol-identifier) & [协议合成延续](#protocol-composition-continuation)
>
#### protocol-composition-continuation {#protocol-composition-continuation}
> *协议合成延续* → [*协议标识符*](#protocol-identifier) | [*协议合成类型*](#protocol-composition-type)
> *协议合成延续* → [协议标识符](#protocol-identifier) | [协议合成类型](#protocol-composition-type)
## 不透明类型 {#opaque-type-h}
@ -393,7 +386,7 @@ typealias PQR = PQ & Q & R
协议声明里不能包括不透明类型。类不能使用不透明类型作为非 final 方法的返回值。
使用不透明类型作为返回值的函数必须返回单一公用底层类型。返回的类型可以包含函数范型类型参的一部分。举个例子,函数 `someFunction<T>()` 可以返回类型 `T` 或者 `Dictionary<String,T>` 的值。
使用不透明类型作为返回值的函数必须返回单一公用底层类型。返回的类型可以包含函数范型类型参的一部分。举个例子,函数 `someFunction<T>()` 可以返回类型 `T` 或者 `Dictionary<String,T>` 的值。
> 不透明类型语法
@ -449,7 +442,7 @@ let anotherInstance = metatype.init(string: "some string")
>
#### metatype-type {#metatype-type}
> *元类型* → [*类型*](#type) **.** **Type** | [*类型*](#type) **.** **Protocol**
> *元类型* → [类型](#type) **.** **Type** | [类型](#type) **.** **Protocol**
## 自身类型 {#self-type-h}
@ -457,7 +450,14 @@ let anotherInstance = metatype.init(string: "some string")
在协议声明或者协议成员声明时,`Self` 类型引用的是最终遵循该协议的类型。
在结构体,类或者枚举值声明时,`Self` 类型引用的是声明的类型。在某个类型成员声明时,`Self` 类型引用的是该类型。在类成员声明时,`Self` 可以在方法的返回值和方法体中使用,但不能在其他上下文中使用。举个例子,下面的代码演示了返回值是 `Self` 的实例方法 `f`
在结构体类或者枚举值声明时Self 类型引用的是声明的类型。在某个类型成员声明时Self 类型引用的是该类型。在类成员声明时,`Self` 只能在以下几种情况中出现:
* 作为方法的返回类型
* 作为只读下标的返回类型
* 作为只读计算属性的类型
* 在方法体中
举个例子,下面的代码演示了返回值是 `Self` 的实例方法 `f`
```swift
class Superclass {
@ -493,25 +493,24 @@ print(type(of: z.f()))
*类型继承子句*被用来指定一个命名型类型继承自哪个类、采纳哪些协议。类型继承子句开始于冒号 `:`,其后是类型标识符列表。
类可以继承自单个超类,并遵循任意数量的协议。当定义一个类时,超类的名字必须出现在类型标识符列表首位,然后跟上该类需要遵循的任意数量的协议。如果一个类不是从其它类继承而来,那么列表可以以协议开头。关于类继承更多的讨论和例子,请参阅 [继承](../chapter2/13_Inheritance.md)。
类可以继承自单个超类,并遵循任意数量的协议。当定义一个类时,超类的名字必须出现在类型标识符列表首位,然后跟上该类需要遵循的任意数量的协议。如果一个类不是从其它类继承而来,那么列表可以以协议开头。关于类继承更多的讨论和例子,请参阅 [继承](../02_language_guide/13_Inheritance.md)。
其它命名型类型只能继承自或采纳一系列协议。协议类型可以继承自任意数量的其他协议。当一个协议类型继承自其它协议时,其它协议中定义的要求会被整合在一起,然后从当前协议继承的任意类型必须符合所有这些条件。
枚举定义中的类型继承子句可以是一系列协议,或者是指定单一的命名类型,此时枚举为其用例分配原始值。在枚举定义中使用类型继承子句来指定原始值类型的例子,请参阅 [原始值](../chapter2/08_Enumerations.md#raw_values)。
枚举定义中的类型继承子句可以是一系列协议,或者是指定单一的命名类型,此时枚举为其用例分配原始值。在枚举定义中使用类型继承子句来指定原始值类型的例子,请参阅 [原始值](../02_language_guide/08_Enumerations.md#raw-values)。
> 类型继承子句语法
>
#### type_inheritance_clause {#type-inheritance-clause}
> *类型继承子句***:** [*类型继承列表*](#type-inheritance-list)
#### type-inheritance-clause {#type-inheritance-clause}
> *类型继承子句***:** [类型继承列表](#type-inheritance-list)
>
#### type-inheritance-list {#type-inheritance-list}
> *类型继承列表* → [*类型标识符*](#type-identifier) | [*类型标识符*](#type-identifier) **,** [*类型继承列表*](#type-inheritance-list)
>
> *类型继承列表* → [类型标识符](#type-identifier) | [类型标识符](#type-identifier) **,** [类型继承列表](#type-inheritance-list)
## 类型推断
Swift 广泛使用*类型推断*,从而允许你省略代码中很多变量和表达式的类型或部分类型。比如,对于 `var x: Int = 0`,你可以完全省略类型而简写成 `var x = 0`,编译器会正确推断出 `x` 的类型 `Int`。类似的,当完整的类型可以从上下文推断出来时,你也可以省略类型的一部分。比如,如果你写了 `let dict: Dictionary = ["A" : 1]`,编译器能推断出 `dict` 的类型是 `Dictionary<String, Int>`
在上面的两个例子中,类型信息从表达式树的叶子节点传向根节点。也就是说,`var x: Int = 0``x` 的类型首先根据 `0` 的类型进行推断,然后将该类型信息传递到根节点(变量 `x`)。

View File

@ -8,33 +8,33 @@ Swift 中存在四种表达式:前缀表达式,二元表达式,基本表
>
#### expression {#expression}
> *表达式* → [*try 运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression) [*二元表达式列表*](#binary-expressions)<sub>可选</sub>
>
> *表达式* → [try 运算符](#try-operator)<sub>可选</sub> [前缀表达式](#prefix-expression) [二元表达式列表](#binary-expressions)<sub>可选</sub>
#### expression-list {#expression-list}
> *表达式列表* → [*表达式*](#expression) | [*表达式*](#expression) **,** [*表达式列表*](#expression-list)
> *表达式列表* → [表达式](#expression) | [表达式](#expression) **,** [表达式列表](#expression-list)
>
## 前缀表达式 {#prefix-expressions}
前缀表达式由可选的前缀运算符和表达式组成。前缀运算符只接收一个参数,表达式则紧随其后。
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/26_Advanced_Operators.md)。
关于这些运算符的更多信息,请参阅 [基本运算符](../02_language_guide/02_Basic_Operators.md) 和 [高级运算符](../02_language_guide/27_Advanced_Operators.md)。
关于 Swift 标准库提供的运算符的更多信息,请参阅 [*Operators Declarations*](https://developer.apple.com/documentation/swift/operator_declarations)。
除了标准库运算符,你也可以对某个变量使用 `&` 运算符,从而将其传递给函数的输入输出参数。更多信息,请参阅 [输入输出参数](../chapter2/06_Functions.md#in_out_parameters)。
除了标准库运算符,你也可以对某个变量使用 `&` 运算符,从而将其传递给函数的输入输出参数。更多信息,请参阅 [输入输出参数](../02_language_guide/06_Functions.md#in-out-parameters)。
> 前缀表达式语法
>
#### prefix-expression {#prefix-expression}
> *前缀表达式* → [*前缀运算符*](./02_Lexical_Structure.md#prefix-operator)<sub>可选</sub> [*后缀表达式*](#postfix-expression)
> *前缀表达式* → [前缀运算符](./02_Lexical_Structure.md#prefix-operator)<sub>可选</sub> [后缀表达式](#postfix-expression)
>
> *前缀表达式* → [*输入输出表达式*](#in-out-expression)
> *前缀表达式* → [输入输出表达式](#in-out-expression)
>
#### in-out-expression {#in-out-expression}
> *输入输出表达式***&** [*标识符*](./02_Lexical_Structure.md#identifier)
> *输入输出表达式***&** [标识符](./02_Lexical_Structure.md#identifier)
>
### Try 运算符 {#try-operator}
@ -67,7 +67,7 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try
`try` 表达式不能出现在二元运算符的的右侧,除非二元运算符是赋值运算符或者 `try` 表达式是被圆括号括起来的。
关于 `try``try?``try!` 的更多信息,以及该如何使用的例子,请参阅 [错误处理](../chapter2/17_Error_Handling.md)。
关于 `try``try?``try!` 的更多信息,以及该如何使用的例子,请参阅 [错误处理](../02_language_guide/17_Error_Handling.md)。
> Try 表达式语法
>
@ -81,7 +81,7 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try
> `左侧参数` `二元运算符` `右侧参数`
>
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/26_Advanced_Operators.md)。
关于这些运算符的更多信息,请参阅 [基本运算符](../02_language_guide/02_Basic_Operators.md) 和 [高级运算符](../02_language_guide/27_Advanced_Operators.md)。
关于 Swift 标准库提供的运算符的更多信息,请参阅 [*Swift Standard Library Operators Reference*](https://developer.apple.com/documentation/swift/operator_declarations)。
@ -94,17 +94,17 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try
#### binary-expression {#binary-expression}
> 二元表达式语法
>
> *二元表达式* → [*二元运算符*](./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)
>
#### binary-expressions {#binary-expressions}
> *二元表达式列表* → [*二元表达式*](#binary-expression) [*二元表达式列表*](#binary-expressions)<sub>可选</sub>
> *二元表达式列表* → [二元表达式](#binary-expression) [二元表达式列表](#binary-expressions)<sub>可选</sub>
>
### 赋值表达式 {#assignment-operator}
@ -137,13 +137,13 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try
如果条件为真,那么对第一个表达式进行求值并返回结果。否则,对第二个表达式进行求值并返回结果。未使用的表达式不会进行求值。
关于使用三元条件运算符的例子,请参阅 [三元条件运算符](../chapter2/02_Basic_Operators.md#ternary_conditional_operator)。
关于使用三元条件运算符的例子,请参阅 [三元条件运算符](../02_language_guide/02_Basic_Operators.md#ternary-conditional-operator)。
> 三元条件运算符语法
>
#### conditional-operator {#conditional-operator}
> *三元条件运算符***?** [*表达式*](#expression) **:**
> *三元条件运算符***?** [表达式](#expression) **:**
>
### 类型转换运算符 {#type-casting-operators}
@ -183,19 +183,19 @@ f(x as Any)
`as!` 运算符执行强制类型转换,返回目标类型的非可选值。如果转换失败,则会导致运行时错误。表达式 `x as! T` 效果等同于 `(x as? T)!`
关于类型转换的更多内容和例子,请参阅 [类型转换](../chapter2/18_Type_Casting.md)。
关于类型转换的更多内容和例子,请参阅 [类型转换](../02_language_guide/18_Type_Casting.md)。
#### type-casting-operator {#type-casting-operator}
> 类型转换运算符语法
>
> *类型转换运算符***is** [*类型*](./03_Types.md#type)
> *类型转换运算符***is** [类型](./03_Types.md#type)
>
> *类型转换运算符***as** [*类型*](./03_Types.md#type)
> *类型转换运算符***as** [类型](./03_Types.md#type)
>
> *类型转换运算符***as** **?** [*类型*](./03_Types.md#type)
> *类型转换运算符***as** **?** [类型](./03_Types.md#type)
>
> *类型转换运算符***as** **!** [*类型*](./03_Types.md#type)
> *类型转换运算符***as** **!** [类型](./03_Types.md#type)
>
## 基本表达式 {#primary-expressions}
@ -205,25 +205,25 @@ f(x as Any)
>
#### primary-expression {#primary-expression}
> *基本表达式* → [*标识符*](./02_Lexical_Structure.md#identifier) [*泛型实参子句*](./09_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub>
> *基本表达式* → [标识符](./02_Lexical_Structure.md#identifier) [泛型实参子句](./09_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)
>
> *基本表达式* → [*隐式成员表达式*](#implicit-member-expression)
> *基本表达式* → [隐式成员表达式](#implicit-member-expression)
>
> *基本表达式* → [*通配符表达式*](#wildcard-expression)
> *基本表达式* → [通配符表达式](#wildcard-expression)
>
> *基本表达式* → [*选择器表达式*](#selector-expression)
> *基本表达式* → [选择器表达式](#selector-expression)
>
> *基本表达式* → [*key-path字符串表达式*](#key-patch-string-expression)
> *基本表达式* → [key-path字符串表达式](#key-patch-string-expression)
>
### 字面量表达式 {#literal-expression}
@ -231,13 +231,20 @@ f(x as Any)
字面量 | 类型 | 值
:------------- | :---------- | :----------
`#file` | `String` | 所在的文件名
`#file` | `String` | 所在的文件名及模块
`#filePath` | `String` | 所在的文件路径
`#line` | `Int` | 所在的行数
`#column` | `Int` | 所在的列数
`#function` | `String` | 所在的声明的名字
`#dsohandle` | `UnsafeRawPointer` | 所使用的 DSO动态共享对象句柄
`#file` 表达式的值的格式是 *module*/*file**file* 是表达式所在的文件名,*module* 是文件所所在的模块名。`#filePath` 表达式的字符串值是表达式所在的文件在整个文件系统里的路径。所有这些值可以被 `#sourceLocation` 改变,详见 [行控制语句](./05_Statements.md#line-control-statements)。
对于 `function`,在函数中会返回当前函数的名字,在方法中会返回当前方法的名字,在属性的存取器中会返回属性的名字,在特殊的成员如 `init``subscript` 中会返回这个关键字的名字,在某个文件中会返回当前模块的名字。
> 注意
>
> 要解析 `#file` 表达式,第一个斜杠(/)之前的文本作为模块名,最后一个斜杠之后的文本作为文件名。将来,该字符串可能包含多个斜杠,例如 `MyModule/some/disambiguation/MyFile.swift`
对于 `#function`,在函数中会返回当前函数的名字,在方法中会返回当前方法的名字,在属性的存取器中会返回属性的名字,在特殊的成员如 `init``subscript` 中会返回这个关键字的名字,在某个文件中会返回当前模块的名字。
当其作为函数或者方法的默认参数值时,该字面量的值取决于函数或方法的调用环境。
@ -283,55 +290,53 @@ Xcode 使用 playground 字面量对程序编辑器中的颜色、文件或者
>
#### literal-expression {#literal-expression}
>
> *字面量表达式* → [*字面量*](./02_Lexical_Structure.md#literal)
> *字面量表达式* → [字面量](./02_Lexical_Structure.md#literal)
>
> *字面量表达式* → [*数组字面量*](#array-literal) | [*字典字面量*](#dictionary-literal) | [*练习场字面量*](#playground-literal)
> *字面量表达式* → [数组字面量](#array-literal) | [字典字面量](#dictionary-literal) | [练习场字面量](#playground-literal)
>
> *字面量表达式***#file** | **#line** | **#column** | **#function**
> *字面量表达式***#file** **#filePath** | **#line** | **#column** | **#function**
>
>
#### array-literal {#array-literal}
>
> *数组字面量* → [[*数组字面量项列表*](#array-literal-items)<sub>可选</sub> **]**
> *数组字面量* → [[数组字面量项列表](#array-literal-items)<sub>可选</sub> **]**
>
>
#### array-literal-items {#array-literal-items}
>
> *数组字面量项列表* → [*数组字面量项*](#array-literal-item) **,**<sub>可选</sub> | [*数组字面量项*](#array-literal-item) **,** [*数组字面量项列表*](#array-literal-items)
> *数组字面量项列表* → [数组字面量项](#array-literal-item) **,**<sub>可选</sub> | [数组字面量项](#array-literal-item) **,** [数组字面量项列表](#array-literal-items)
>
>
#### array-literal-item {#array-literal-item}
>
> *数组字面量项* → [*表达式*](#expression)
> *数组字面量项* → [表达式](#expression)
>
>
>
#### dictionary-literal {#dictionary-literal}
>
> *字典字面量* → [[*字典字面量项列表*](#dictionary-literal-items) **]** | **[** **:** **]**
> *字典字面量* → [[字典字面量项列表](#dictionary-literal-items) **]** | **[** **:** **]**
>
>
#### dictionary-literal-items {#dictionary-literal-items}
>
> *字典字面量项列表* → [*字典字面量项*](#dictionary-literal-item) **,**<sub>可选</sub> | [*字典字面量项*](#dictionary-literal-item) **,** [*字典字面量项列表*](#dictionary-literal-items)
> *字典字面量项列表* → [字典字面量项](#dictionary-literal-item) **,**<sub>可选</sub> | [字典字面量项](#dictionary-literal-item) **,** [字典字面量项列表](#dictionary-literal-items)
>
>
#### dictionary-literal-item {#dictionary-literal-item}
>
> *字典字面量项* → [*表达式*](#expression) **:** [*表达式*](#expression)。
> *字典字面量项* → [表达式](#expression) **:** [表达式](#expression)。
>
>
#### playground-literal {#playground-literal}
>
> *playground 字面量***#colorLiteral ( red : [*表达式*](#expression) , green :[*表达式*](#expression) [*表达式*](#e[*表达式*](#expression) xpression) , blue :[*表达式*](#expression) , alpha : [*表达式*](#expression) )**
> *playground 字面量***#colorLiteral ( red : [表达式](#expression) , green :[表达式](#expression) [表达式](#e[*表达式*](#expression) xpression) , blue :[表达式](#expression) , alpha : [表达式](#expression) )**
>
> *playground 字面量***#fileLiteral ( resourceName : [*表达式*](#expression) )**
>
>
#### playground 字面量* → **#imageLiteral ( resourceName : [*表达式*](#expression) )**self_expression {#self-expression}
> *playground 字面量***#fileLiteral ( resourceName : [表达式](#expression) )**
>
> #### playground 字面量* → **#imageLiteral ( resourceName : [表达式](#expression) )**self-expression {#self-expression}
### Self 表达式
@ -376,16 +381,16 @@ struct Point {
>
#### self-expression {#self-expression}
> *self 表达式***self** | [*self 方法表达式*](#self-method-expression) [*self 下标表达式*](#self-subscript-expression) | [*self 构造器表达式*](#self-initializer-expression)
> *self 表达式***self** | [self 方法表达式](#self-method-expression) [self 下标表达式](#self-subscript-expression) | [self 构造器表达式](#self-initializer-expression)
>
>
#### self-method-expression {#self-method-expression}
> *self 方法表达式***self** **.** [*标识符*](./02_Lexical_Structure.md#identifier)
> *self 方法表达式***self** **.** [标识符](./02_Lexical_Structure.md#identifier)
>
#### self-subscript-expression {#self-subscript-expression}
> *self 下标表达式***self** **[** [*函数调用参数表*](#function-call-argument-list­) **]**
> *self 下标表达式***self** **[** [函数调用参数表](#function-call-argument-list­) **]**
>
#### self-initializer-expression {#self-initializer-expression}
@ -410,15 +415,15 @@ struct Point {
>
#### superclass-expression {#superclass-expression}
> *父类表达式* → [*父类方法表达式*](#superclass-method-expression) | [*父类下标表达式*](#superclass-subscript-expression) | [*父类构造器表达式*](#superclass-initializer-expression)
> *父类表达式* → [父类方法表达式](#superclass-method-expression) | [父类下标表达式](#superclass-subscript-expression) | [父类构造器表达式](#superclass-initializer-expression)
>
#### superclass-method-expression {#superclass-method-expression}
> *父类方法表达式***super** **.** [*标识符*](./02_Lexical_Structure.md#identifier)
> *父类方法表达式***super** **.** [标识符](./02_Lexical_Structure.md#identifier)
>
#### superclass-subscript-expression {#superclass-subscript-expression}
> *父类下标表达式***super** [[*函数调用参数表*](#function-call-argument-list­) **]**
> *父类下标表达式***super** [[函数调用参数表](#function-call-argument-list­) **]**
>
#### superclass-initializer-expression {#superclass-initializer-expression}
@ -434,7 +439,7 @@ struct Point {
}
```
闭包的参数声明形式跟函数一样,请参阅 [函数声明](./06_Declarations.md#function_declaration)。
闭包的参数声明形式跟函数一样,请参阅 [函数声明](./06_Declarations.md#function-declaration)。
闭包还有几种特殊的形式,能让闭包使用起来更加简洁:
@ -460,11 +465,11 @@ myFunction { return $0 + $1 }
myFunction { $0 + $1 }
```
关于如何将闭包作为参数来传递的内容,请参阅 [函数调用表达式](#function_call_expression)。
关于如何将闭包作为参数来传递的内容,请参阅 [函数调用表达式](#function-call-expression)。
使用闭包表达式时,可以不必将其存储在一个变量或常量中,例如作为函数调用的一部分来立即使用一个闭包。在上面的例子中,传入 `myFunction` 的闭包表达式就是这种立即使用类型的闭包。因此,一个闭包是否逃逸与其使用时的上下文相关。一个会被立即调用或者作为函数的非逃逸参数传递的闭包表达式是非逃逸的,否则,这个闭包表达式是逃逸的。
关于逃逸闭包的内容,请参阅 [逃逸闭包](./chapter2/07_Closures.md#escaping_closures)。
关于逃逸闭包的内容,请参阅 [逃逸闭包](../02_language_guide/07_Closures.md#escaping-closures)。
## 捕获列表 {#capture-lists}
默认情况下,闭包会捕获附近作用域中的常量和变量,并使用强引用指向它们。你可以通过一个*捕获列表*来显式指定它的捕获行为。
@ -522,7 +527,7 @@ myFunction { [unowned self] in print(self.title) } // 无主引用捕获
myFunction { [weak parent = self.parent] in print(parent!.title) }
```
关于闭包表达式的更多信息和例子,请参阅 [闭包表达式](../chapter2/07_Closures.md#closure_expressions)。关于捕获列表的更多信息和例子,请参阅 [解决闭包引起的循环强引用](../chapter2/23_Automatic_Reference_Counting.md#resolving_strong_reference_cycles_for_closures)。
关于闭包表达式的更多信息和例子,请参阅 [闭包表达式](../02_language_guide/07_Closures.md#closure-expressions)。关于捕获列表的更多信息和例子,请参阅 [解决闭包引起的循环强引用](../02_language_guide/24_Automatic_Reference_Counting.md#resolving-strong-reference-cycles-for-closures)。
> 闭包表达式语法
>
@ -530,39 +535,39 @@ myFunction { [weak parent = self.parent] in print(parent!.title) }
>
#### closure-expression {#closure-expression}
>
> *闭包表达式***{** [*闭包签名*](#closure-signature)<sub>可选</sub> [*语句*](#statements) **}**
> *闭包表达式***{** [闭包签名](#closure-signature)<sub>可选</sub> [语句](#statements) **}**
>
>
>
#### closure-signature {#closure-signature}
>
>
> 闭包签名* → [*参数子句*](#parameter-clause) [*函数结果*](05_Declarations.md#function-result)<sub>可选</sub> **in**
> 闭包签名* → [参数子句](#parameter-clause) [函数结果](./06_Declarations.md#function-result)<sub>可选</sub> **in**
>
> *闭包签名* → [*标识符列表*](#identifier-list) [*函数结果*](05_Declarations.md#function-result)<sub>可选</sub> **in**
> *闭包签名* → [标识符列表](#identifier-list) [函数结果](./06_Declarations.md#function-result)<sub>可选</sub> **in**
>
> *闭包签名* → [*捕获列表*](#capture-list) [*参数子句*](05_Declarations.md#parameter-clause) [*函数结果*](./06_Declarations.md#function-result)<sub>可选</sub> **in**
> *闭包签名* → [捕获列表](#capture-list) [参数子句](./06_Declarations.md#parameter-clause) [函数结果](./06_Declarations.md#function-result)<sub>可选</sub> **in**
>
> *闭包签名* → [*捕获列表*](#capture-list) [*标识符列表*](02_Lexical_Structure.md#identifier-list) [*函数结果*](./06_Declarations.md#function-result)<sub>可选</sub> **in**
> *闭包签名* → [捕获列表](#capture-list) [标识符列表](./02_Lexical_Structure.md#identifier-list) [函数结果](./06_Declarations.md#function-result)<sub>可选</sub> **in**
>
> *闭包签名* → [*捕获列表*](#capture-list) **in**
> *闭包签名* → [捕获列表](#capture-list) **in**
>
>
>
#### capture-list {#capture-list}
>
>
> 捕获列表* → [ [*捕获列表项列表*](#capture-list-items) **]**
> 捕获列表* → [ [捕获列表项列表](#capture-list-items) **]**
>
>
#### capture-list-items {#capture-list-items}
>
> *捕获列表项列表* → [*捕获列表项*](#capture-list-item) | [*捕获列表项*](#capture-list-item) **,** [*捕获列表项列表*](#capture-list-items)
> *捕获列表项列表* → [捕获列表项](#capture-list-item) | [捕获列表项](#capture-list-item) **,** [捕获列表项列表](#capture-list-items)
>
>
#### capture-list-item {#capture-list-item}
>
> *捕获列表项* → [*捕获说明符*](#capture-specifier)<sub>可选</sub> [*表达式*](#expression)
> *捕获列表项* → [捕获说明符](#capture-specifier)<sub>可选</sub> [表达式](#expression)
>
>
#### capture-specifier {#capture-specifier}
@ -587,7 +592,7 @@ x = .AnotherValue
>
#### implicit-member-expression {#implicit-member-expression}
> *隐式成员表达式***.** [*标识符*](./02_Lexical_Structure.md#identifier)
> *隐式成员表达式***.** [标识符](./02_Lexical_Structure.md#identifier)
>
### 圆括号表达式 {#parenthesized-expression}
@ -597,7 +602,7 @@ x = .AnotherValue
>
#### parenthesized-expression {#parenthesized-expression}
> *圆括号表达式***( [*表达式*](#expression) )**
> *圆括号表达式***( [表达式](#expression) )**
>
### 元组表达式 {#Tuple-Expression}
@ -606,6 +611,8 @@ x = .AnotherValue
> (`标识符 1` : `表达式 1`, `标识符 2` : `表达式 2`, `...`)
>
元组表达式里的每一个标识符在表达式作用域里必须是唯一的。在嵌套的元组表达式中,同嵌套层级里的标识符也必须是唯一的。例如,`(a: 10, a: 20)` 是不合法的,因为标签 `a` 在同一层级出现了两次。然而,`(a: 10, b: (a: 1, x: 2))` 是合法的,尽管 `a` 出现了两次,但有一次在外层元组里,一次在内层元组里。
元组表达式可以一个表达式都没有,也可以包含两个或是更多的表达式。单个表达式用括号括起来就是括号表达式了。
> 注意
@ -619,15 +626,15 @@ x = .AnotherValue
>
#### tuple-expression {#tuple-expression}
> *元组表达式***( )** | **(**[*元组元素*](#tuple-element) [*元组元素列表*](#tuple-element-list) **)**
> *元组表达式***( )** | **(**[元组元素](#tuple-element) [元组元素列表](#tuple-element-list) **)**
>
#### tuple-element-list {#tuple-element-list}
> *元组元素列表* → [*元组元素*](#tuple-element) | [*元组元素*](#tuple-element) **,** [*元组元素列表*](#tuple-element-list)
> *元组元素列表* → [元组元素](#tuple-element) | [元组元素](#tuple-element) **,** [元组元素列表](#tuple-element-list)
>
#### tuple-element {#tuple-element}
> *元组元素* → [*表达式*](#expression) | [*标识符*](identifier) **:** [*表达式*](#expression)
> *元组元素* → [表达式](#expression) | [标识符](#identifier) **:** [表达式](#expression)
>
### 通配符表达式 {#wildcard-expression}
@ -676,7 +683,7 @@ let value = s[keyPath: pathToProperty]
```swift
class SomeClass: NSObject {
@objc var someProperty: Int
@objc dynamic var someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
}
@ -756,7 +763,7 @@ print(count as Any)
// 打印 "Optional(5)"
```
可以混合使用各种 key-path 组件来访问一些深度嵌套类型的值。下面的代码通过组合不同的组件,使用 key-path 表达式访问了一个字典数组中不同的值和属性。
可以混合使用各种 key path 组件来访问一些深度嵌套类型的值。下面的代码通过组合不同的组件,使用 key-path 表达式访问了一个字典数组中不同的值和属性。
```swift
let interestingNumbers = ["prime": [2, 3, 5, 7, 11, 13, 17],
@ -772,7 +779,40 @@ print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth
// 打印 "64"
```
关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) 和 [Key-Value 观察编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i)
你可以在平时提供函数或者闭包的上下文里使用 key path 表达式。特别地,你可以用根类型是 `SomeType` 和路径产生 `Value` 类型值的 key path 表达式来替换类型是 `(SomeType) -> Value` 的函数或者闭包
```swift
struct Task {
var description: String
var completed: Bool
}
var toDoList = [
Task(description: "Practice ping-pong.", completed: false),
Task(description: "Buy a pirate costume.", completed: true),
Task(description: "Visit Boston in the Fall.", completed: false),
]
// 下面两种写法是等价的。
let descriptions = toDoList.filter(\.completed).map(\.description)
let descriptions2 = toDoList.filter { $0.completed }.map { $0.description }
```
任何 key path 表达式的副作用发生的关键在于表达式在哪里被执行。例如,如果你在 key path 表达式中的一个下标里使用函数调用,该函数只会在表达式计算的时候调用一次,而不是每次这个 key path 被使用的时候。
```swift
func makeIndex() -> Int {
print("Made an index")
return 0
}
// 下面这行调用 makeIndex()。
let taskKeyPath = \[Task][makeIndex()]
// 打印 "Made an index"
// 使用 taskKeyPath 不会再次调用 makeIndex()。
let someTask = toDoList[keyPath: taskKeyPath]
```
关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple-ref/doc/uid/10000107i) 和 [Key-Value 观察编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple-ref/doc/uid/10000177i)。
> key-path 表达式语法
>
@ -823,7 +863,7 @@ class SomeClass: NSObject {
self.property = property
}
}
let selectorForMethod = #selector(SomeClass.doSomething(_:))
let selectorForMethod = #selector(SomeClass.doSomething(-:))
let selectorForPropertyGetter = #selector(getter: SomeClass.property)
```
@ -836,7 +876,7 @@ extension SomeClass {
@objc(doSomethingWithString:)
func doSomething(_ x: String) { }
}
let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void)
let anotherSelector = #selector(SomeClass.doSomething(-:) as (SomeClass) -> (String) -> Void)
```
由于选择器是在编译时创建的,因此编译器可以检查方法或者属性是否存在,以及是否在运行时暴露给了 Objective-C 。
@ -852,11 +892,11 @@ let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (Str
>
#### selector-expression {#selector-expression}
> *选择器表达式*__#selector__ **(** [*表达式*](#expression) **)**
> *选择器表达式*__#selector-- **(** [表达式](#expression) **)**
>
> *选择器表达式*__#selector__ **(** [*getter:表达式*](#expression) **)**
> *选择器表达式*__#selector-- **(** [getter:表达式](#expression) **)**
>
> *选择器表达式*__#selector__ **(** [*setter:表达式*](#expression) **)**
> *选择器表达式*__#selector-- **(** [setter:表达式](#expression) **)**
>
## Key-path 字符串表达式 {#key-path-string-expressions}
@ -899,7 +939,7 @@ print(keyPath == c.getSomeKeyPath())
由于 key-path 字符串表达式在编译期才创建,编译期可以检查属性是否存在,以及属性是否暴露给 Objective-C 运行时。
关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](./https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.md#//apple_ref/doc/uid/10000107i) 和 [Key-Value 观察编程](./https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.md#//apple_ref/doc/uid/10000177i)。
关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.md#//apple-ref/doc/uid/10000107i) 和 [Key-Value 观察编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.md#//apple-ref/doc/uid/10000177i)。
> 注意
>
@ -918,7 +958,7 @@ print(keyPath == c.getSomeKeyPath())
## 后缀表达式 {#postfix-expressions}
*后缀表达式*就是在某个表达式的后面运用后缀运算符或其他后缀语法。从语法构成上来看,基本表达式也是后缀表达式。
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/26_Advanced_Operators.md)。
关于这些运算符的更多信息,请参阅 [基本运算符](../02_language_guide/02_Basic_Operators.md) 和 [高级运算符](../02_language_guide/27_Advanced_Operators.md)。
关于 Swift 标准库提供的运算符的更多信息,请参阅 [运算符定义](https://developer.apple.com/documentation/swift/operator_declarations)。
@ -926,25 +966,25 @@ print(keyPath == c.getSomeKeyPath())
>
#### postfix-expression {#postfix-expression}
> *后缀表达式* → [*基本表达式*](#primary-expression)
> *后缀表达式* → [基本表达式](#primary-expression)
>
> *后缀表达式* → [*后缀表达式*](#postfix-expression) [*后缀运算符*](02_Lexical_Structure.md#postfix-operator)
> *后缀表达式* → [后缀表达式](#postfix-expression) [后缀运算符](./02_Lexical_Structure.md#postfix-operator)
>
> *后缀表达式* → [*函数调用表达式*](#function-call-expression)
> *后缀表达式* → [函数调用表达式](#function-call-expression)
>
> *后缀表达式* → [*构造器表达式*](#initializer-expression)
> *后缀表达式* → [构造器表达式](#initializer-expression)
>
> *后缀表达式* → [*显式成员表达式*](#explicit-member-expression)
> *后缀表达式* → [显式成员表达式](#explicit-member-expression)
>
> *后缀表达式* → [*后缀 self 表达式*](#postfix-self-expression)
> *后缀表达式* → [后缀 self 表达式](#postfix-self-expression)
>
> *后缀表达式* → [*dynamicType 表达式*](#dynamic-type-expression)
> *后缀表达式* → [dynamicType 表达式](#dynamic-type-expression)
>
> *后缀表达式* → [*下标表达式*](#subscript-expression)
> *后缀表达式* → [下标表达式](#subscript-expression)
>
> *后缀表达式* → [*强制取值表达式*](#forced-value-expression)
> *后缀表达式* → [强制取值表达式](#forced-value-expression)
>
> *后缀表达式* → [*可选链表达式*](#optional-chaining-expression)
> *后缀表达式* → [可选链表达式](#optional-chaining-expression)
>
### 函数调用表达式 {#function-call-expression}
@ -958,14 +998,17 @@ print(keyPath == c.getSomeKeyPath())
如果函数声明中指定了参数的名字,那么在调用的时候也必须得写出来。这种函数调用表达式具有以下形式:
> `函数名`(`参数名 1`: `参数 1`, `参数名 2`: `参数 2`)
>
如果函数的最后一个参数是函数类型,可以在函数调用表达式的尾部(右圆括号之后)加上一个闭包,该闭包会作为函数的最后一个参数。如下两种写法是等价的:
```swift
// someFunction 接受整和闭包参
// someFunction 接受整和闭包的实
someFunction(x, f: {$0 == 13})
someFunction(x) {$0 == 13}
// anotherFunction 接受一个整型和两个闭包的实参
anotherFunction(x: x, f: { $0 == 13 }, g: { print(99) })
anotherFunction(x: x) { $0 == 13 } g: { print(99) }
```
如果闭包是该函数的唯一参数,那么圆括号可以省略。
@ -976,39 +1019,43 @@ myData.someMethod() {$0 == 13}
myData.someMethod {$0 == 13}
```
如 [特殊名称方法](./06_Declarations.md#methods-with-special-names) 所述,通过声明几种方法中的一种,类、结构体或枚举类型可以为函数调用语法启用语法糖。
> 函数调用表达式语法
>
>
#### function-call-expression {#function-call-expression}
>
> *函数调用表达式* → [*后缀表达式*](#postfix-expression) [*函数调用参数子句*](#function-call-argument-clause)
> *函数调用表达式* → [后缀表达式](#postfix-expression) [函数调用参数子句](#function-call-argument-clause)
>
> *函数调用表达式* → [*后缀表达式*](#postfix-expression) [*函数调用参数子句*](#function-call-argument-clause)<sub>可选</sub> [*尾随闭包*](#trailing-closure)
> *函数调用表达式* → [后缀表达式](#postfix-expression) [函数调用参数子句](#function-call-argument-clause)<sub>可选</sub> [尾随闭包](#trailing-closure)
>
>#### function-call-argument-clause {#function-call-argument-clause}
>
> *函数调用参数子句***(** **)** | **(** [函数调用参数表](#function-call-argument-list) **)**
>
#### function-call-argument-clause {#function-call-argument-clause}
>
> *函数调用参数子句***(** **)** | **(** [*函数调用参数表*](#function-call-argument-list) **)**
>
>
#### function-call-argument-list {#function-call-argument-list}
> #### function-call-argument-list {#function-call-argument-list}
>
> *函数调用参数表* → [函数调用参数](#function-call-argument) | [函数调用参数](#function-call-argument) **,** [*函数调用参数表*](#function-call-argument-list)
>
>
#### function-call-argument {#function-call-argument}
> #### function-call-argument {#function-call-argument}
>
> *函数调用参数* → [表达式](#expression) | [标识符](02_Lexical_Structure.md#identifier) **:** [*表达式*](#expression)
> *函数调用参数* → [表达式](#expression) | [标识符](./02_Lexical_Structure.md#identifier) **:** [表达式](#expression)
>
> *函数调用参数* → [运算符](./02_Lexical_Structure.md#operator) | [标识符](./02_Lexical_Structure.md#identifier) **:** [*运算符*](./02_Lexical_Structure.md#operator)
> *函数调用参数* → [运算符](./02_Lexical_Structure.md#operator) | [标识符](./02_Lexical_Structure.md#identifier) **:** [运算符](./02_Lexical_Structure.md#operator)
>
> #### trailing-closure {#trailing-closure}
>
> *尾随闭包* → [闭包表达式](#closure-expression)
>
> #### labeled-trailing-closures {#labeled-trailing-closures}
>
#### trailing-closure {#trailing-closure}
>
> *尾随闭包* → [*闭包表达式*](#closure-expression)
> *标签尾随闭包集* → [标签尾随闭包](#labeled-trailing-closure) [标签尾随闭包集](#labeled-trailing-closures)<sub>可选</sub>
>
> #### labeled-trailing-closure {#labeled-trailing-closure}
> *标签尾随闭包* → [标识符](./02_Lexical_Structure.md#identifier) **:** [闭包表达式](#closure-expression)
### 构造器表达式 {#initializer-expression}
*构造器表达式*用于访问某个类型的构造器,形式如下:
@ -1051,9 +1098,9 @@ let s3 = someValue.dynamicType.init(data: 7) // 有效
>
#### initializer-expression {#initializer-expression}
> *构造器表达式* → [*后缀表达式*](#postfix-expression) **.** **init**
> *构造器表达式* → [后缀表达式](#postfix-expression) **.** **init**
>
> *构造器表达式* → [*后缀表达式*](#postfix-expression) **.** **init** **(** [*参数名称*](#argument-names) **)**
> *构造器表达式* → [后缀表达式](#postfix-expression) **.** **init** **(** [参数名称](#argument-names) **)**
>
### 显式成员表达式 {#explicit-member-expression}
@ -1116,19 +1163,17 @@ let x = [10, 3, 20, 15, 4]
>
#### explicit-member-expression {#explicit-member-expression}
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*十进制数字*] (02_Lexical_Structure.md#decimal-digit)
> *显式成员表达式* → [后缀表达式](#postfix-expression) **.** [十进制数字](./02_Lexical_Structure.md#decimal-digit)
>
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*标识符*](02_Lexical_Structure.md#identifier) [*泛型实参子句*](./09_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub><br/>
>
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*标识符*] (02_Lexical_Structure.md#identifier) **(** [*参数名称*](#argument-names) **)**
> *显式成员表达式* → [后缀表达式](#postfix-expression) **.** [标识符](./02_Lexical_Structure.md#identifier) [泛型实参子句](./09_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub><br/>
>
> *显式成员表达式* → [后缀表达式](#postfix-expression) **.** [标识符](./02_Lexical_Structure.md#identifier) **(** [参数名称](#argument-names) **)**
#### argument-names {#argument-names}
> *参数名称* → [*参数名*](#argument-name) [*参数名称*](#argument-names)<sub>可选</sub><br/>
>
> *参数名称* → [参数名](#argument-name) [参数名称](#argument-names)<sub>可选</sub><br/>
#### argument-name {#argument-name}
> *参数名* → [*标识符*](./02_Lexical_Structure.md#identifier) **:**
> *参数名* → [标识符](./02_Lexical_Structure.md#identifier) **:**
>
### 后缀 self 表达式 {#postfix-self-expression}
@ -1147,7 +1192,7 @@ let x = [10, 3, 20, 15, 4]
>
#### postfix-self-expression {#postfix-self-expression}
> *后缀 self 表达式* → [*后缀表达式*](#postfix-expression) **.** **self**
> *后缀 self 表达式* → [后缀表达式](#postfix-expression) **.** **self**
>
@ -1159,13 +1204,13 @@ let x = [10, 3, 20, 15, 4]
要获取下标表达式的值,可将索引表达式作为下标表达式的参数来调用下标 getter。下标 setter 的调用方式与之一样。
关于下标的声明,请参阅 [协议下标声明](./06_Declarations.md#protocol_subscript_declaration)。
关于下标的声明,请参阅 [协议下标声明](./06_Declarations.md#protocol-subscript-declaration)。
> 下标表达式语法
>
#### subscript-expression {#subscript-expression}
> *下标表达式* → [*后缀表达式*](#postfix-expression) **[** [*表达式列表*](#expression-list) **]**
> *下标表达式* → [后缀表达式](#postfix-expression) **[** [表达式列表](#expression-list) **]**
>
### 强制取值表达式 {#forced-Value-expression}
@ -1192,7 +1237,7 @@ someDictionary["a"]![0] = 100
>
#### forced-value-expression {#forced-value-expression}
> *强制取值表达式* → [*后缀表达式*](#postfix-expression) **!**
> *强制取值表达式* → [后缀表达式](#postfix-expression) **!**
>
### 可选链表达式 {#optional-chaining-expression}
@ -1244,5 +1289,4 @@ someDictionary["a"]?[0] = someFunctionWithSideEffects()
>
#### optional-chaining-expression {#optional-chaining-expression}
> *可选链表达式* → [*后缀表达式*](#postfix-expression) **?**
>
> *可选链表达式* → [后缀表达式](#postfix-expression) **?**

View File

@ -8,42 +8,41 @@
> 语句语法
>
> *语句* → [*表达式*](./04_Expressions.md#expression) **;**<sub>可选</sub>
> *语句* → [表达式](./04_Expressions.md#expression) **;**<sub>可选</sub>
>
> *语句* → [*声明*](./06_Declarations.md#declaration) **;**<sub>可选</sub>
> *语句* → [声明](./06_Declarations.md#declaration) **;**<sub>可选</sub>
>
> *语句* → [*循环语句*](#loop-statement) **;**<sub>可选</sub>
> *语句* → [循环语句](#loop-statement) **;**<sub>可选</sub>
>
> *语句* → [*分支语句*](#branch-statement) **;**<sub>可选</sub>
> *语句* → [分支语句](#branch-statement) **;**<sub>可选</sub>
>
> *语句* → [*带标签的语句*](#labeled-statement) **;**<sub>可选</sub>
> *语句* → [带标签的语句](#labeled-statement) **;**<sub>可选</sub>
>
> *语句* → [*控制转移语句*](#control-transfer-statement) **;**<sub>可选</sub>
> *语句* → [控制转移语句](#control-transfer-statement) **;**<sub>可选</sub>
>
> *语句* → [*defer 语句*](#defer-statement) **;**<sub>可选</sub>
> *语句* → [defer 语句](#defer-statement) **;**<sub>可选</sub>
>
> *语句* → [*do 语句*](#do-statement) **:**<sub>可选</sub>
> *语句* → [do 语句](#do-statement) **:**<sub>可选</sub>
>
> *语句* → [*编译器控制语句*](#compiler-control-statement)
>
> *多条语句* → [*语句*](#statement) [*多条语句*](#statements)<sub>可选</sub>
> *语句* → [编译器控制语句](#compiler-control-statement)
>
> *多条语句* → [语句](#statement) [多条语句](#statements)<sub>可选</sub>
## 循环语句 {#loop-statements}
循环语句会根据特定的循环条件来重复执行代码块。Swift 提供三种类型的循环语句:`for-in` 语句、`while` 语句和 `repeat-while` 语句。
通过 `break` 语句和 `continue` 语句可以改变循环语句的控制流。有关这两条语句,详情参 [Break 语句](#break_statement) 和 [Continue 语句](#continue_statement)。
通过 `break` 语句和 `continue` 语句可以改变循环语句的控制流。有关这两条语句,详情参 [Break 语句](#break-statement) 和 [Continue 语句](#continue-statement)。
> 循环语句语法
>
>
#### loop-statement {#loop-statement}
> *循环语句* → [*for-in 语句*](#for-in-statement)
> *循环语句* → [for-in 语句](#for-in-statement)
>
> *循环语句* → [*while 语句*](#while-statement)
> *循环语句* → [while 语句](#while-statement)
>
> *循环语句* → [*repeat-while 语句*](#repeat-while-statement)
> *循环语句* → [repeat-while 语句](#repeat-while-statement)
>
### For-In 语句 {#for-in-statements}
@ -65,7 +64,7 @@ for item in collection {
>
#### for-in-statement {#for-in-statement}
> *for-in 语句***for** **case**<sub>可选</sub> [*模式*](./08_Patterns.md#pattern) **in** [*表达式*](./04_Expressions.md#expression) [*where 子句*](#where-clause)<sub>可选</sub> [*代码块*](05_Declarations.md#code-block)
> *for-in 语句***for** **case**<sub>可选</sub> [模式](./08_Patterns.md#pattern) **in** [表达式](./04_Expressions.md#expression) [where 子句](#where-clause)<sub>可选</sub> [代码块](./06_Declarations.md#code-block)
>
### While 语句 {#while-statements}
@ -86,32 +85,32 @@ while condition {
由于会在执行循环体中的语句前判断条件的值,因此循环体中的语句可能会被执行若干次,也可能一次也不会被执行。
条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../02_language_guide/01_The_Basics.md#optional-binding)。
> while 语句语法
>
>
#### while-statement {#while-statement}
> *while 语句***while** [*条件子句*](#condition-clause) [*代码块*](./05_Declarations.md#code-block)
> *while 语句***while** [条件子句](#condition-clause) [代码块](./06_Declarations.md#code-block)
>
#### condition-clause {#condition-clause}
> *条件子句* → [*表达式*](./04_Expressions.md#expression) | [*表达式*](./04_Expressions.md#expression) **,** [*条件列表*](#condition-list)
> *条件子句* → [表达式](./04_Expressions.md#expression) | [表达式](./04_Expressions.md#expression) **,** [条件列表](#condition-list)
>
#### condition {#condition}
> *条件* → [*表达式*](./04_Expressions.md#expression) |[*可用性条件*](#availability-condition) | [*case 条件*](#case-condition) | [*可选绑定条件*](#optional-binding-condition)
> *条件* → [表达式](./04_Expressions.md#expression) |[可用性条件](#availability-condition) | [case 条件](#case-condition) | [可选绑定条件](#optional-binding-condition)
>
>
#### case-condition {#case-condition}
> *case 条件***case** [*模式*](./08_Patterns.md#pattern) [*构造器*](./06_Declarations.md#initializer)
> *case 条件***case** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer)
>
#### optional-binding-condition {#optional-binding-condition}
> *可选绑定条件***let** [*模式*](./08_Patterns.md#pattern) [*构造器*](./06_Declarations.md#initializer) | **var** [*模式*](./08_Patterns.md#pattern) [*构造器*](./06_Declarations.md#initializer)
> *可选绑定条件***let** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer) | **var** [模式](./08_Patterns.md#pattern) [构造器](./06_Declarations.md#initializer)
>
### Repeat-While 语句 {#repeat-while-statements}
@ -132,31 +131,31 @@ repeat {
由于条件的值是在循环体中的语句执行后才进行判断,因此循环体中的语句至少会被执行一次。
条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../02_language_guide/01_The_Basics.md#optional-binding)。
> repeat-while 语句语法
>
>
#### repeat-while-statement {#repeat-while-statement}
> *repeat-while 语句***repeat** [*代码块*](./06_Declarations.md#code-block) **while** [*表达式*](./04_Expressions.md#expression)
> *repeat-while 语句***repeat** [代码块](./06_Declarations.md#code-block) **while** [表达式](./04_Expressions.md#expression)
>
## 分支语句 {#branch-statements}
分支语句会根据一个或者多个条件来执行指定部分的代码。分支语句中的条件将会决定程序如何分支以及执行哪部分代码。Swift 提供三种类型的分支语句:`if` 语句、 `guard` 语句和 `switch` 语句。
`if` 语句和 `switch` 语句中的控制流可以用 `break` 语句改变,请参阅 [Break 语句](#break_statement)。
`if` 语句和 `switch` 语句中的控制流可以用 `break` 语句改变,请参阅 [Break 语句](#break-statement)。
> 分支语句语法
>
>
#### branch-statement {#branch-statement}
> *分支语句* → [*if 语句*](#if-statement)
> *分支语句* → [if 语句](#if-statement)
>
> *分支语句* → [*guard 语句*](#guard-statement)
> *分支语句* → [guard 语句](#guard-statement)
>
> *分支语句* → [*switch 语句*](#switch-statement)
> *分支语句* → [switch 语句](#switch-statement)
>
### If 语句 {#if-statements}
@ -194,19 +193,18 @@ if condition 1 {
}
```
`if` 语句中条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
`if` 语句中条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件语句也可以使用可选绑定,请参阅 [可选绑定](../02_language_guide/01_The_Basics.md#optional-binding)。
> if 语句语法
>
>
#### if-statement {#if-statement}
> *if 语句***if** [*条件子句*](#condition-clause) [*代码块*](05_Declarations.md#code-block) [*else 子句*](#else-clause)<sub>可选</sub>
> *if 语句***if** [条件子句](#condition-clause) [代码块](./06_Declarations.md#code-block) [else 子句](#else-clause)<sub>可选</sub>
>
#### else-clause {#else-clause}
> *else 子句***else** [*代码块*](./06_Declarations.md#code-block) | **else** [*if 语句*](#if-statement)
>
> *else 子句***else** [代码块](./06_Declarations.md#code-block) | **else** [if 语句](#if-statement)
### Guard 语句 {#guard-statements}
如果一个或者多个条件不成立,可用 `guard` 语句来退出当前作用域。
@ -219,7 +217,7 @@ guard condition else {
}
```
`guard` 语句中条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件也可以是一条可选绑定,请参阅 [可选绑定](../chapter2/01_The_Basics.md#optional_binding)。
`guard` 语句中条件的结果必须是 Bool 类型或者 Bool 的桥接类型。另外,条件也可以是一条可选绑定,请参阅 [可选绑定](../02_language_guide/01_The_Basics.md#optional-binding)。
`guard` 语句中进行可选绑定的任何常量或者变量,其可用范围从声明开始直到作用域结束。
@ -230,17 +228,17 @@ guard condition else {
* `continue`
* `throw`
关于控制转移语句,请参阅 [控制转移语句](#control_transfer_statements)。关于 `Never` 返回类型的函数,请参阅 [永不返回的函数](05_Declarations.md#rethrowing_functions_and_methods)。
关于控制转移语句,请参阅 [控制转移语句](#control-transfer-statements)。关于 `Never` 返回类型的函数,请参阅 [永不返回的函数](./06_Declarations.md#rethrowing-functions-and-methods)。
> guard 语句语法
>
>
#### guard-statement {#guard-statement}
> *guard 语句***guard** [*条件子句*](#condition-clause) **else** [*代码块*] (05_Declarations.md#code-block)
>
> *guard 语句***guard** [条件子句](#condition-clause) **else** [代码块](./06_Declarations.md#code-block)
### Switch 语句 {#switch-statements}
`switch` 语句会根据控制表达式的值来决定执行哪部分代码。
`switch` 语句的形式如下:
@ -261,7 +259,7 @@ default:
`switch` 语句会先计算*控制表达式*的值,然后与每一个 `case` 的模式进行匹配。如果匹配成功,程序将会执行对应的 `case` 中的语句。另外,每一个 `case` 的作用域都不能为空,也就是说在每一个 `case` 的冒号(`:`)后面必须至少有一条语句。如果你不想在匹配到的 `case` 中执行代码,只需在该 `case` 中写一条 `break` 语句即可。
可以用作控制表达式的值是十分灵活的。除了标量类型外,如 `Int``Character`,你可以使用任何类型的值,包括浮点数、字符串、元组、自定义类型的实例和可选类型。控制表达式的值还可以用来匹配枚举类型中的成员值或是检查该值是否包含在指定的 `Range` 中。关于如何在 `switch` 语句中使用这些类型,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章中的 [Switch](../chapter2/05_Control_Flow.md#switch)。
可以用作控制表达式的值是十分灵活的。除了标量类型外,如 `Int``Character`,你可以使用任何类型的值,包括浮点数、字符串、元组、自定义类型的实例和可选类型。控制表达式的值还可以用来匹配枚举类型中的成员值或是检查该值是否包含在指定的 `Range` 中。关于如何在 `switch` 语句中使用这些类型,请参阅 [控制流](../02_language_guide/05_Control_Flow.md) 一章中的 [Switch](../02_language_guide/05_Control_Flow.md#switch)。
每个 `case` 的模式后面可以有一个 `where` 子句。`where` 子句由 `where` 关键字紧跟一个提供额外条件的表达式组成。因此,当且仅当控制表达式匹配一个 `case` 的模式且 `where` 子句的表达式为真时,`case` 中的语句才会被执行。在下面的例子中,控制表达式只会匹配包含两个相等元素的元组,例如 `(1, 1)`
@ -280,7 +278,7 @@ case let (x, y) where x == y:
在 Swift 中,`switch` 语句中控制表达式的每一个可能的值都必须至少有一个 `case` 与之对应。在某些无法面面俱到的情况下(例如,表达式的类型是 `Int`),你可以使用 `default` 分支满足该要求。
#### 对未来枚举的 `case` 进行 `switch` {#future-case}
非冻结枚举(`nonfronzen enumeration`)是一种特殊的枚举类型,它可能在未来会增加新的枚举 `case`,即使这时候你已经编译并且发布了你的应用,所以在 switch 非冻结枚举前需要深思熟虑。当一个库的作者们把一个枚举标记为非冻结的,这意味着他们保留了增加新的枚举 `case` 的权利,并且任何和这个枚举交互的代码都要在不需要重新编译的条件下能够处理那些未来可能新加入的 `case` 。只有那些标准库,比如用 Swift 实现的苹果的一些框架C 以及 Objective-C 代码才能够声明非冻结枚举。你在 Swift 中声明的枚举不能是非冻结的
非冻结枚举(`nonfronzen enumeration`)是一种特殊的枚举类型,它可能在未来会增加新的枚举 `case`,即使这时候你已经编译并且发布了你的应用,所以在 switch 非冻结枚举前需要深思熟虑。当一个库的作者们把一个枚举标记为非冻结的,这意味着他们保留了增加新的枚举 `case` 的权利,并且任何和这个枚举交互的代码都*必须*在无需重新编译的条件下能够处理那些未来可能新加入的 `case` 。只有演进模式的库代码、标准库代码、用 Swift 实现的 Apple 框架C 以及 Objective-C 代码才能够声明非冻结枚举。更多关于冻结和非冻结枚举的内容,请参阅 [冻结](./07_Attributes.md#frozen)
当你对未来枚举进行 switch 时,你总是需要有一个 `default case`,即使每种枚举类型都已经有对应的 `case` 了。你可以在 default 前标注 `@unknown`,意思是这个 `case` 应该只匹配未来加入的枚举 `case`。如果你的 `default case` 中匹配了任何在编译时就能确定的枚举 `case`Swift 会抛出一个警告。这可以很好地提醒你库的作者已经新增了一种 `case`,并且你还没有去处理。
@ -303,94 +301,94 @@ case .suppressed:
#### 不存在隐式落入
当匹配到的 `case` 中的代码执行完毕后,`switch` 语句会直接退出,而不会继续执行下一个 `case` 。这就意味着,如果你想执行下一个 `case`,需要显式地在当前 `case` 中使用 `fallthrough` 语句。关于 `fallthrough` 语句的更多信息,请参阅 [Fallthrough 语句](#fallthrough_statements)。
当匹配到的 `case` 中的代码执行完毕后,`switch` 语句会直接退出,而不会继续执行下一个 `case` 。这就意味着,如果你想执行下一个 `case`,需要显式地在当前 `case` 中使用 `fallthrough` 语句。关于 `fallthrough` 语句的更多信息,请参阅 [Fallthrough 语句](#fallthrough-statements)。
> switch 语句语法
>
>
#### switch-statement {#switch-statement}
> *switch 语句***switch** [*表达式*](./04_Expressions.md#expression) **{** [*switch-case 列表*](#switch-cases)<sub>可选</sub> **}**
> *switch 语句***switch** [表达式](./04_Expressions.md#expression) **{** [switch-case 列表](#switch-cases)<sub>可选</sub> **}**
>
#### switch-cases {#switch-cases}
> *switch case 列表* → [*switch-case*](#switch-case) [*switch-case 列表*](#switch-cases)<sub>可选</sub>
> *switch case 列表* → [switch-case](#switch-case) [switch-case 列表](#switch-cases)<sub>可选</sub>
>
#### switch-case {#switch-case}
> *switch case* → [*case 标签*](#case-label) [*多条语句*](#statements) | [*default 标签*](#default-label) [*多条语句*](#statements) | [*conditional-switch-case*](#conditional-switch-case-label)
> *switch case* → [case 标签](#case-label) [多条语句](#statements) | [default 标签](#default-label) [多条语句](#statements) | [conditional-switch-case](#conditional-switch-case-label)
>
#### case-label {#case-label}
> *case 标签* → [*属性*](#switch-case-attributes-label)<sub>可选</sub> **case** [*case 项列表*](#case-item-list) **:**
> *case 标签* → [属性](#switch-case-attributes-label)<sub>可选</sub> **case** [case 项列表](#case-item-list) **:**
>
#### case-item-list {#case-item-list}
> *case 项列表* → [*模式*](./08_Patterns.md#pattern) [*where 子句*](#where-clause)<sub>可选</sub> | [*模式*](07_Patterns.md#pattern) [*where 子句*](#where-clause)<sub>可选</sub> **,** [*case 项列表*](#case-item-list)
> *case 项列表* → [模式](./08_Patterns.md#pattern) [where 子句](#where-clause)<sub>可选</sub> | [模式](./08_Patterns.md#pattern) [where 子句](#where-clause)<sub>可选</sub> **,** [case 项列表](#case-item-list)
>
#### default-label {#default-label}
> *default 标签* → [*属性*](#switch-case-attributes-label)<sub>可选</sub> **default** **:**
> *default 标签* → [属性](#switch-case-attributes-label)<sub>可选</sub> **default** **:**
>
>
#### where-clause {#where-clause}
> *where-clause***where** [*where 表达式*](#where-expression)
> *where-clause***where** [where 表达式](#where-expression)
>
#### where-expression {#where-expression}
> *where-expression* → [*表达式*](./04_Expressions.md#expression)
> *where-expression* → [表达式](./04_Expressions.md#expression)
>
>
#### grammar_conditional-switch-case {#grammar-conditional-switch-case}
> *conditional-switch-case* → [*switch-if-directive-clause*](#switch-case-attributes-label) [*switch-elseif-directive-clauses*](#switch-case-attributes-label) <sub>可选</sub> [*switch-else-directive-clause*](#switch-case-attributes-label) <sub>可选</sub> [*endif-directive*](#switch-case-attributes-label)
#### grammar-conditional-switch-case {#grammar-conditional-switch-case}
> *conditional-switch-case* → [switch-if-directive-clause](#switch-case-attributes-label) [switch-elseif-directive-clauses](#switch-case-attributes-label) <sub>可选</sub> [switch-else-directive-clause](#switch-case-attributes-label) <sub>可选</sub> [endif-directive](#switch-case-attributes-label)
>
#### grammar_switch-if-directive-clause {#grammar-switch-if-directive-clause}
> *switch-if-directive 语句* → [*if-directive*](#switch-case-attributes-label) [*compilation-condition*](#switch-case-attributes-label) [*switch-cases*](#switch-case-attributes-label) <sub>可选</sub>
#### grammar-switch-if-directive-clause {#grammar-switch-if-directive-clause}
> *switch-if-directive 语句* → [if-directive](#switch-case-attributes-label) [compilation-condition](#switch-case-attributes-label) [switch-cases](#switch-case-attributes-label) <sub>可选</sub>
>
#### grammar_switch-elseif-directive-clauses {#grammar-switch-elseif-directive-clauses}
> *switch-elseif-directive 语句(复数)* → [*elseif-directive-clause*](#switch-case-attributes-label) [*switch-elseif-directive-clauses*](#switch-case-attributes-label)<sub>可选</sub>
#### grammar-switch-elseif-directive-clauses {#grammar-switch-elseif-directive-clauses}
> *switch-elseif-directive 语句(复数)* → [elseif-directive-clause](#switch-case-attributes-label) [switch-elseif-directive-clauses](#switch-case-attributes-label)<sub>可选</sub>
>
#### grammar_switch-elseif-directive-clause {#grammar-switch-elseif-directive-clause}
> *switch-elseif-directive 语句* → [*elseif-directive*](#switch-case-attributes-label) [*compilation-condition*](#switch-case-attributes-label) [*switch-cases*](#switch-case-attributes-label)<sub>可选</sub>
#### grammar-switch-elseif-directive-clause {#grammar-switch-elseif-directive-clause}
> *switch-elseif-directive 语句* → [elseif-directive](#switch-case-attributes-label) [compilation-condition](#switch-case-attributes-label) [switch-cases](#switch-case-attributes-label)<sub>可选</sub>
>
#### grammar_switch-else-directive-clause {#grammar-switch-else-directive-clause}
> *switch-else-directive 语句* → [*else-directive*](#switch-case-attributes-label) [*switch-cases*](#switch-case-attributes-label) <sub>可选</sub>
#### grammar-switch-else-directive-clause {#grammar-switch-else-directive-clause}
> *switch-else-directive 语句* → [else-directive](#switch-case-attributes-label) [switch-cases](#switch-case-attributes-label) <sub>可选</sub>
>
## 带标签的语句 {#labeled-statements}
你可以在循环语句或 `switch` 语句前面加上标签,它由标签名和紧随其后的冒号(`:`)组成。在 `break``continue` 后面跟上标签名可以显式地在循环语句或 `switch` 语句中改变相应的控制流。关于这两条语句用法,请参阅 [Break 语句](#break_statement) 和 [Continue 语句](#continue_statement)。
你可以在循环语句或 `switch` 语句前面加上标签,它由标签名和紧随其后的冒号(`:`)组成。在 `break``continue` 后面跟上标签名可以显式地在循环语句或 `switch` 语句中改变相应的控制流。关于这两条语句用法,请参阅 [Break 语句](#break-statement) 和 [Continue 语句](#continue-statement)。
标签的作用域在该标签所标记的语句内。可以嵌套使用带标签的语句,但标签名必须唯一。
关于使用带标签的语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章中的 [带标签的语句](../chapter2/05_Control_Flow.md#labeled_statements)。
关于使用带标签的语句的例子,请参阅 [控制流](../02_language_guide/05_Control_Flow.md) 一章中的 [带标签的语句](../02_language_guide/05_Control_Flow.md#labeled-statements)。
> 带标签的语句语法
>
>
#### labeled-statement {#labeled-statement}
> *带标签的语句* → [*语句标签*](#statement-label) [*循环语句*](#grammar_loop-statement)
> *带标签的语句* → [语句标签](#statement-label) [循环语句](#grammar-loop-statement)
>
> *带标签的语句* → [*语句标签*](#statement-label) [*if 语句*](#if-statement)
> *带标签的语句* → [语句标签](#statement-label) [if 语句](#if-statement)
>
> *带标签的语句* → [*语句标签*](#statement-label) [*switch 语句*](#switch-statement)
> *带标签的语句* → [语句标签](#statement-label) [switch 语句](#switch-statement)
>
> > *带标签的语句* → [*语句标签*](#statement-label) [*do 语句*](#sdo-statement)
> > *带标签的语句* → [语句标签](#statement-label) [do 语句](#sdo-statement)
>
#### statement-label {#statement-label}
> *语句标签* → [*标签名称*](#label-name) **:**
> *语句标签* → [标签名称](#label-name) **:**
>
#### label-name {#label-name}
> *标签名称* → [*标识符*](./02_Lexical_Structure.md#identifier)
> *标签名称* → [标识符](./02_Lexical_Structure.md#identifier)
>
## 控制转移语句 {#control-transfer-statements}
@ -401,15 +399,15 @@ case .suppressed:
>
#### control-transfer-statement {#control-transfer-statement}
> *控制转移语句* → [*break 语句*](#break-statement)
> *控制转移语句* → [break 语句](#break-statement)
>
> *控制转移语句* → [*continue 语句*](#continue-statement)
> *控制转移语句* → [continue 语句](#continue-statement)
>
> *控制转移语句* → [*fallthrough 语句*](#fallthrough-statement)
> *控制转移语句* → [fallthrough 语句](#fallthrough-statement)
>
> *控制转移语句* → [*return 语句*](#return-statement)
> *控制转移语句* → [return 语句](#return-statement)
>
> *控制转移语句* → [*throw 语句*](#throw-statement)
> *控制转移语句* → [throw 语句](#throw-statement)
>
### Break 语句 {#break-statement}
@ -426,14 +424,14 @@ case .suppressed:
无论哪种情况,控制权都会被转移给被终止的控制流语句后面的第一行语句。
关于使用 `break` 语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章的 [Break](../chapter2/05_Control_Flow.md#break) 和 [带标签的语句](../chapter2/05_Control_Flow.md#labeled_statements)。
关于使用 `break` 语句的例子,请参阅 [控制流](../02_language_guide/05_Control_Flow.md) 一章的 [Break](../02_language_guide/05_Control_Flow.md#break) 和 [带标签的语句](../02_language_guide/05_Control_Flow.md#labeled-statements)。
> break 语句语法
>
>
#### break-statement {#break-statement}
> *break 语句***break** [*标签名称*](#label-name)<sub>可选</sub>
> *break 语句***break** [标签名称](#label-name)<sub>可选</sub>
>
### Continue 语句 {#continue-statement}
@ -452,14 +450,14 @@ case .suppressed:
`for` 语句中,`continue` 语句执行后,增量表达式还是会被计算,这是因为每次循环体执行完毕后,增量表达式都会被计算。
关于使用 `continue` 语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章的 [Continue](../chapter2/05_Control_Flow.md#continue) 和 [带标签的语句](../chapter2/05_Control_Flow.md#labeled_statements)。
关于使用 `continue` 语句的例子,请参阅 [控制流](../02_language_guide/05_Control_Flow.md) 一章的 [Continue](../02_language_guide/05_Control_Flow.md#continue) 和 [带标签的语句](../02_language_guide/05_Control_Flow.md#labeled-statements)。
> continue 语句语法
>
>
#### continue-statement {#continue-statement}
> *continue 语句***continue** [*标签名称*](#label-name)<sub>可选</sub>
> *continue 语句***continue** [标签名称](#label-name)<sub>可选</sub>
>
### Fallthrough 语句 {#fallthrough-statements}
@ -467,7 +465,7 @@ case .suppressed:
`fallthrough` 语句可出现在 `switch` 语句中的任意 `case` 中,但不能出现在最后一个 `case` 中。同时,`fallthrough` 语句也不能把控制权转移到使用了值绑定的 `case`
关于在 `switch` 语句中使用 `fallthrough` 语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章的 [控制转移语句](../chapter2/05_Control_Flow.md#control_transfer_statements)。
关于在 `switch` 语句中使用 `fallthrough` 语句的例子,请参阅 [控制流](../02_language_guide/05_Control_Flow.md) 一章的 [控制转移语句](../02_language_guide/05_Control_Flow.md#control-transfer-statements)。
> fallthrough 语句语法
>
@ -492,7 +490,7 @@ case .suppressed:
> 注意
>
>
> 正如 [可失败构造器](./06_Declarations.md#failable_initializers) 中所描述的,`return nil` 在可失败构造器中用于表明构造失败。
> 正如 [可失败构造器](./06_Declarations.md#failable-initializers) 中所描述的,`return nil` 在可失败构造器中用于表明构造失败。
>
而只写 `return` 时,仅仅是从该函数或方法中返回,而不返回任何值(也就是说,函数或方法的返回类型为 `Void` 或者说 `()`)。
@ -502,11 +500,10 @@ case .suppressed:
>
#### return-statement {#return-statement}
> *return 语句***return** [*表达式*](./04_Expressions.html#expression)<sub>可选</sub>
> *return 语句***return** [表达式](./04_Expressions.md#expression)<sub>可选</sub>
### Throw 语句 {#throw-statements}
### Throw 语句 {#throw-statements}
`throw` 语句出现在抛出函数或者抛出方法体内,或者类型被 `throws` 关键字标记的闭包表达式体内。
`throw` 语句使程序在当前作用域结束执行,并向外围作用域传播错误。抛出的错误会一直传递,直到被 `do` 语句的 `catch` 子句处理掉。
@ -518,14 +515,14 @@ case .suppressed:
表达式的结果必须符合 `ErrorType` 协议。
关于如何使用 `throw` 语句的例子,请参阅 [错误处理](../chapter2/17_Error_Handling.md) 一章的 [用 throwing 函数传递错误](../chapter2/17_Error_Handling.md#propagating_errors_using_throwing_functions)。
关于如何使用 `throw` 语句的例子,请参阅 [错误处理](../02_language_guide/17_Error_Handling.md) 一章的 [用 throwing 函数传递错误](../02_language_guide/17_Error_Handling.md#propagating-errors-using-throwing-functions)。
> throw 语句语法
>
>
#### throw-statement {#throw-statement}
> *throw 语句***throw** [*表达式*](./04_Expressions.md#expression)
> *throw 语句***throw** [表达式](./04_Expressions.md#expression)
>
## Defer 语句 {#defer-statements}
@ -562,7 +559,7 @@ f()
>
#### defer-statement {#defer-statement}
> *延迟语句***defer** [*代码块*](./06_Declarations.md#code-block)
> *延迟语句***defer** [代码块](./06_Declarations.md#code-block)
>
## Do 语句 {#do-statements}
@ -580,30 +577,43 @@ do {
statements
} catch pattern 2 where condition {
statements
} catch pattern 3, pattern 4 where condition {
statements
} catch {
statements
}
```
`switch` 语句,编译器会判断 `catch` 子句是否有遗漏。如果 `catch` 子句没有遗漏,则认为错误已被处理。否则,错误会自动传递到外作用域,被某个 `catch` 子句处理掉或者被用 `throws` 关键字声明的抛出函数继续向外抛出
`do` 代码块中的任何语句抛出了错误,程序会跳转到第一个能模式匹配该错误的 `catch` 子句。如果没有任何子句匹配,错误会传递到外层作作用域。如果错误在最顶层依旧没有被处理,程序执行会因为运行时错误而停止
如同 `switch` 语句,编译器会判断 `catch` 子句是否有遗漏。如果 `catch` 子句没有遗漏,则认为错误已被处理。否则,错误会自动传递到外层作用域,被某个 `catch` 子句处理掉或者被用 `throws` 关键字声明的抛出函数继续向外抛出。
拥有多个模式匹配的 `catch` 子句只需其中一个匹配到错误即可。如果 `catch` 子句拥有多个模式匹配,所有的模式必须包含相同的绑定常量或变量,并且每个 `catch` 子句里所有绑定的变量或常量的类型必须相同。
为了确保错误已经被处理,可以让 `catch` 子句使用匹配所有错误的模式,如通配符模式(`_`)。如果一个 `catch` 子句不指定一种具体模式,`catch` 子句会匹配任何错误,并绑定到名为 `error` 的局部常量。有关在 `catch` 子句中使用模式的更多信息,请参阅 [模式](./08_Patterns.md)。
关于如何在 `do` 语句中使用一系列 `catch` 子句的例子,请参阅 [错误处理](../chapter2/17_Error_Handling.md#handling_errors)。
关于如何在 `do` 语句中使用一系列 `catch` 子句的例子,请参阅 [错误处理](../02_language_guide/17_Error_Handling.md#handling-errors)。
> do 语句语法
>
>
#### do-statement {#do-statement}
> *do 语句***do** [*代码块*](./06_Declarations.md#code-block) [*多条 catch 子句*](#catch-clauses)<sub>可选</sub>
> *do 语句***do** [代码块](./06_Declarations.md#code-block) [多条 catch 子句](#catch-clauses)<sub>可选</sub>
>
#### catch-clauses {#catch-clauses}
> *多条 catch 子句* → [*catch 子句*](#catch-clause) [*多条 catch 子句*](#catch-clauses)<sub>可选</sub>
> *多条 catch 子句* → [catch 子句](#catch-clause) [多条 catch 子句](#catch-clauses)<sub>可选</sub>
>
#### catch-clause {#catch-clause}
> *catch 子句***catch** [*模式*](./08_Patterns.md#pattern)<sub>可选</sub> [*where 子句*](#where-clause)<sub>可选</sub> [*代码块*](05_Declarations.md#code-block)
>
> *catch 子句***catch** [模式](./08_Patterns.md#pattern)<sub>可选</sub> [where 子句](#where-clause)<sub>可选</sub> [代码块](./06_Declarations.md#code-block)
#### catch-pattern-list{#catch-pattern-list}
> *catch 模式列表* → [catch 模式](#catch-pattern) | [catch 模式](#catch-pattern) [catch 模式列表](#catch-pattern-list)
#### catch-pattern{#catch-pattern}
> *catch 模式* → [模式](./08_Patterns.md#pattern) [where 子句](./05_Statements.md#where-clause)<sub>可选</sub>
## 编译器控制语句 {#compiler-control-statements}
编译器控制语句允许程序改变编译器的行为。Swift 有三种编译器控制语句:条件编译语句、线路控制语句和编译时诊断语句。
@ -613,14 +623,15 @@ do {
>
#### compiler-control-statement {#compiler-control-statement}
> *编译器控制语句* → [*条件编译语句*](#grammar_conditional-compilation-block)
> *编译器控制语句* → [条件编译语句](#grammar-conditional-compilation-block)
>
> *编译器控制语句* → [*线路控制语句*](#line-control-statement)
> *编译器控制语句* → [线路控制语句](#line-control-statement)
>
> *编译器控制语句* → [*诊断语句*](#grammar_diagnostic-statement)
> *编译器控制语句* → [诊断语句](#grammar-diagnostic-statement)
>
### 条件编译代码块 {#Conditional-Compilation-Block}
条件编译代码块可以根据一个或多个配置来有条件地编译代码。
每一个条件编译代码块都以 `#if` 开始,`#endif` 结束。如下:
@ -642,7 +653,7 @@ statements
| `swift()` | `>=``<` 后跟版本号 |
| `compiler()` | `>=``<` 后跟版本号 |
| `canImport()` | 模块名 |
| `targetEnvironment()` | 模拟器 |
| `targetEnvironment()` | `simulator``macCatalyst` |
`swift()``compiler()` 之后的版本号包含有主版本号,可选副版本号,可选补丁版本号类似,并且用(`.`)来分隔。在比较符和版本号之间不能有空格,版本号与前面的函数相对应,比如 `compiler()` 对应的就是这个编译器的版本号,`swift()` 对应的就是你要编译的 `Swift` 语言的版本号。举个简单的例子,如果你在使用 `Swift 5` 的编译器,想编译 `Swift 4.2` ,可以看下面的例子:
@ -697,24 +708,24 @@ statements to compile if both compilation conditions are false
>
>
#### grammar_conditional-compilation-block {#grammar-conditional-compilation-block}
> *条件编译代码块* → [*if-directive 语句*](#grammar_if-directive-clause) [*elseif-directive 语句(复数)*](#grammar_elseif-directive-clauses)<sub>可选</sub> [*else-directive 语句*](#grammar_else-directive-clause)<sub>可选</sub> [*endif-directive*](#grammar_endif-directive)
#### grammar-conditional-compilation-block {#grammar-conditional-compilation-block}
> *条件编译代码块* → [if-directive 语句](#grammar-if-directive-clause) [elseif-directive 语句(复数)](#grammar-elseif-directive-clauses)<sub>可选</sub> [else-directive 语句](#grammar-else-directive-clause)<sub>可选</sub> [endif-directive](#grammar-endif-directive)
>
#### grammar_if-directive-clause {#grammar-if-directive-clause}
> *if-directive 语句* → [*if-directive*](#grammar_if-directive) [*编译条件*](#compilation-condition) [*语句(复数)*](#statements)<sub>可选</sub>
#### grammar-if-directive-clause {#grammar-if-directive-clause}
> *if-directive 语句* → [if-directive](#grammar-if-directive) [编译条件](#compilation-condition) [语句(复数)](#statements)<sub>可选</sub>
>
#### grammar_elseif-directive-clauses {#grammar-elseif-directive-clauses}
> *elseif-directive 语句(复数)* → [*elseif-directive 语句*](#grammar_elseif-directive-clause) [*elseif-directive 语句(复数)*](#grammar_elseif-directive-clauses)
#### grammar-elseif-directive-clauses {#grammar-elseif-directive-clauses}
> *elseif-directive 语句(复数)* → [elseif-directive 语句](#grammar-elseif-directive-clause) [elseif-directive 语句(复数)](#grammar-elseif-directive-clauses)
>
#### grammar_elseif-directive-clauses {#grammar-elseif-directive-clauses}
> *elseif-directive 语句* → [*elseif-directive*](#grammar_elseif-directive) [*编译条件*](#compilation-condition) [*语句(复数)*](#statements)<sub>可选</sub>
#### grammar-elseif-directive-clauses {#grammar-elseif-directive-clauses}
> *elseif-directive 语句* → [elseif-directive](#grammar-elseif-directive) [编译条件](#compilation-condition) [语句(复数)](#statements)<sub>可选</sub>
>
#### grammar_else-directive-clause {#grammar-else-directive-clause}
> *else-directive 语句* → [*else-directive*](#grammar_else-directive) [*语句(复数)*](#statements)<sub>可选</sub>
#### grammar-else-directive-clause {#grammar-else-directive-clause}
> *else-directive 语句* → [else-directive](#grammar-else-directive) [语句(复数)](#statements)<sub>可选</sub>
>
@ -729,47 +740,41 @@ statements to compile if both compilation conditions are false
#### compilation-condition {#compilation-condition}
> *编译条件* → [*平台条件*](#grammar_platform-condition)
> *编译条件* → [平台条件](#grammar-platform-condition)
>
> *编译条件* → [*标识符*](./02_Lexical_Structure.md#identifier)
> *编译条件* → [标识符](./02_Lexical_Structure.md#identifier)
>
> *编译条件* → [*布尔值字面量*](./02_Lexical_Structure.md#boolean-literal)
> *编译条件* → [布尔值字面量](./02_Lexical_Structure.md#boolean-literal)
>
> *编译条件***(** [*编译条件*](#compilation-condition) **)**
> *编译条件***(** [编译条件](#compilation-condition) **)**
>
> *编译条件***!** [*编译条件*](#compilation-condition)
> *编译条件***!** [编译条件](#compilation-condition)
>
> *编译条件* → [*编译条件*](#compilation-condition) **&&** [*编译条件*](#compilation-condition)
> *编译条件* → [编译条件](#compilation-condition) **&&** [编译条件](#compilation-condition)
>
> *编译条件* → [*编译条件*](#compilation-condition) **||** [*编译条件*](#compilation-condition)
> *编译条件* → [编译条件](#compilation-condition) **||** [编译条件](#compilation-condition)
>
#### grammar_platform-condition {#grammar-platform-condition}
#### grammar-platform-condition {#grammar-platform-condition}
#### grammar_platform-condition-os {#grammar-platform-condition-os}
> *平台条件* → **os ( [*操作系统*](#operating-system) )**
>
#### grammar-platform-condition-os {#grammar-platform-condition-os}
> *平台条件* → **os ( [操作系统](#operating-system) )**
#### grammar_platform-condition-arch {#grammar-platform-condition-arch}
> *平台条件* → **arch ( [*架构*](#architecture) )**
>
#### grammar-platform-condition-arch {#grammar-platform-condition-arch}
> *平台条件* → **arch ( [架构](#architecture) )**
#### grammar_platform-condition-swift {#grammar-platform-condition-swift}
> *平台条件***swift ( >= [*swift 版本*](#swift-version) )** | **swift ( < [*swift 版本*](#swift-version) )**
>
#### grammar-platform-condition-swift {#grammar-platform-condition-swift}
> *平台条件***swift ( >= [swift 版本](#swift-version) )** | **swift ( < [swift 版本](#swift-version) )**
#### grammar_platform-condition-compiler {#grammar-platform-condition-compiler}
> *平台条件***compiler ( >= [*swift 版本*](#swift-version) )** | **compiler ( < [*swift 版本*](#swift-version) )**
>
#### grammar-platform-condition-compiler {#grammar-platform-condition-compiler}
> *平台条件***compiler ( >= [swift 版本](#swift-version) )** | **compiler ( < [swift 版本](#swift-version) )**
#### grammar_platform-condition-canImport {#grammar-platform-condition-canImport}
> *平台条件* → **canImport ( [*模块名*](#grammar_module-name) )**
>
#### grammar-platform-condition-canImport {#grammar-platform-condition-canImport}
> *平台条件* → **canImport ( [模块名](#grammar-module-name) )**
#### grammar_platform-condition-targetEnvironment {#grammar-platform-condition-targetEnvironment}
> *平台条件* → **targetEnvironment ( [*环境*](#grammar_environment) )**
>
#### grammar-platform-condition-targetEnvironment {#grammar-platform-condition-targetEnvironment}
> *平台条件* → **targetEnvironment ( [环境](#grammar-environment) )**
#### operating-system {#operating-system}
> *操作系统***macOS** | **iOS** | **watchOS** | **tvOS**
@ -780,33 +785,28 @@ statements to compile if both compilation conditions are false
>
#### swift-version {#swift-version}
> *swift 版本* → [*十进制数字*](./02_Lexical_Structure.md#decimal-digit) ­**.** ­[*swift 版本延续*](#grammar_swift-version-continuation) <sub>可选</sub>
>
> *swift 版本* → [十进制数字](./02_Lexical_Structure.md#decimal-digit) ­**.** ­[swift 版本延续](#grammar-swift-version-continuation) <sub>可选</sub>
#### grammar_swift-version-continuation {#grammar-swift-version-continuation}
> *swift 版本延续***.** [*十进制数字*](./02_Lexical_Structure.md#decimal-digit) [*swift 版本延续*](#grammar_swift-version-continuation) <sub>可选</sub>
>
#### grammar-swift-version-continuation {#grammar-swift-version-continuation}
> *swift 版本延续***.** [十进制数字](./02_Lexical_Structure.md#decimal-digit) [swift 版本延续](#grammar-swift-version-continuation) <sub>可选</sub>
#### grammar_module-name {#grammar-module-name}
> *模块名* → [*identifier*](./02_Lexical_Structure.md#identifier)
>
#### grammar-module-name {#grammar-module-name}
> *模块名* → [identifier](./02_Lexical_Structure.md#identifier)
#### grammar_environment {#grammar-environment}
> *环境* → **模拟器**
>
#### grammar-environment {#grammar-environment}
> *环境***模拟器** | **macCatalyst**
### 行控制语句 {#line-control-statements}
行控制语句可以为被编译的源代码指定行号和文件名,从而改变源代码的定位信息,以便进行分析和调试。
行控制语句形式如下:
> \#sourceLocation(file: `filename` , line:`line number`)
>
> #sourceLocation(file: file path, line: line number)
>
> #sourceLocation()
> \#sourceLocation()
>
第一种的行控制语句会改变该语句之后的代码中的字面量表达式 `#line``#file` 所表示的值。`行号` 是一个大于 0 的整形字面量,会改变 `#line` 表达式的值。`文件名` 是一个字符串字面量,会改变 `#file` 表达式的值。
第一种的行控制语句会改变该语句之后的代码中的字面量表达式 `#line``#file``#filePath` 所表示的值,从行控制语句里行号的代码开始。`行号` 是一个大于 0 的整形字面量,会改变 `#line` 表达式的值。`文件名` 是一个字符串字面量,会改变 `#file``#filePath` 表达式的值。指定的字符串会变成 `#filePath` 的值,且字符串最后的路径部分会变成 `#file` 的值。
第二种的行控制语句,`#sourceLocation()`,会将源代码的定位信息重置回默认的行号和文件名。
@ -814,19 +814,17 @@ statements to compile if both compilation conditions are false
#### line-control-statement {#line-control-statement}
> 行控制语句语法
>
>
> *行控制语句***#sourceLocation(file:[*文件名*](#file-name),line:[*行号*](#line-number))**
>
> *行控制语句***#sourceLocation()**
>*行控制语句* → **#sourceLocation(file:[文件名](#file-name),line:[行号](#line-number))**
>
> *行控制语句***#sourceLocation( )**
#### line-number {#line-number}
> *行号* → 大于 0 的十进制整数
>
#### file-name {#file-name}
> *文件名* → [*静态字符串字面量*](./02_Lexical_Structure.md#static-string-literal)
>
> *文件名* → [静态字符串字面量](./02_Lexical_Structure.md#static-string-literal)
### 编译时诊断语句 {#compile-time-diagnostic-statement}
@ -843,15 +841,15 @@ statements to compile if both compilation conditions are false
>
>
#### grammar_compile-time-diagnostic-statement {#grammar-compile-time-diagnostic-statement}
> *诊断语句***#error** **(** [*diagnostic-message*](#grammar_diagnostic-message) **)**
#### grammar-compile-time-diagnostic-statement {#grammar-compile-time-diagnostic-statement}
> *诊断语句***#error** **(** [诊断消息](#grammar-diagnostic-message) **)**
>
> *诊断语句***#warning** **(** [*diagnostic-message*](#grammar_diagnostic-message) **)**
>
> *诊断语句* → [*静态字符串字面量*](./02_Lexical_Structure.md#static-string-literal)
> *诊断语句***#warning** **(** [诊断消息](#grammar-diagnostic-message) **)**
>
> *诊断语句* → [静态字符串字面量](./02_Lexical_Structure.md#static-string-literal)
## 可用性条件 {#availability-condition}
可用性条件可作为 `if``while``guard` 语句的条件,可以在运行时基于特定的平台参数来查询 API 的可用性。
可用性条件的形式如下:
@ -875,12 +873,10 @@ if #available(platform name version, ..., *) {
>
#### availability-condition {#availability-condition}
> *可用性条件***#available** **(** [*可用性参数列表*](#availability-arguments) **)**
>
> *可用性条件***#available** **(** [可用性参数列表](#availability-arguments) **)**
#### availability-arguments {#availability-arguments}
> *可用性参数列表* → [*可用性参数*](#availability-argument) | [*可用性参数*](#availability-argument) **,** [*可用性参数列表*](#availability-arguments)
>
> *可用性参数列表* → [可用性参数](#availability-argument) | [可用性参数](#availability-argument) **,** [可用性参数列表](#availability-arguments)
#### availability-argument {#availability-argument}
> *可用性参数* → [平台名称](#platform-name) [平台版本](#platform-version)
@ -905,4 +901,3 @@ if #available(platform name version, ..., *) {
> *平台版本* → [十进制数字](./02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](./02_Lexical_Structure.md#decimal-digits)
>
> *平台版本* → [十进制数字](./02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](./02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](./02_Lexical_Structure.md#decimal-digits)
>

View File

@ -0,0 +1,505 @@
# 特性Attributes
在 Swift 中有两种特性,分别用于修饰声明和类型。特性提供了有关声明和类型的更多信息。例如,使用 `discardableResult` 特性声明的函数,表明该函数虽然有返回值,但如果没有使用该返回值,编译器不会产生警告。
您可以通过以下方式指定一个特性,通过符号 `@` 后跟特性的名称和特性接收的任何参数:
@`特性名`
@`特性名`(`特性参数`)
有些声明特性通过接收参数来指定特性的更多信息以及它是如何修饰某个特定的声明的。这些_特性的参数_写在圆括号内它们的格式由它们所属的特性来定义。
## 声明特性 {#declaration-attributes}
声明特性只能应用于声明。
### `available` {#available}
`available` 特性用于声明时,表示该声明的生命周期是相对于特定的平台和操作系统版本。
`available` 特性经常与参数列表一同出现,该参数列表至少有两个特性参数,参数之间由逗号分隔。这些参数由以下这些平台名字中的一个起头:
- `iOS`
- `iOSApplicationExtension`
- `macOS`
- `macOSApplicationExtension`
- `watchOS`
- `watchOSApplicationExtension`
- `tvOS`
- `tvOSApplicationExtension`
- `swift`
当然,你也可以用一个星号(`*`)来表示上面提到的所有平台。指定 Swift 版本的 `available` 特性参数,不能使用星号表示。
其余的参数,可以按照任何顺序出现,并且可以添加关于声明生命周期的附加信息,包括重要事件。
- `unavailable` 参数表示该声明在指定的平台上是无效的。当指定 Swift 版本可用性时不可使用该参数。
- `introduced` 参数表示指定平台从哪一版本开始引入该声明。格式如下:
`introduced`: `版本号`
*版本号*由一至三个正整数构成,由句点分隔的。
- `deprecated` 参数表示指定平台从哪一版本开始弃用该声明。格式如下:
`deprecated`: `版本号`
可选的*版本号*由一个或多个正整数构成,由句点分隔的。省略版本号表示该声明目前已弃用,而不提供有关弃用发生时间的任何信息。如果你省略了版本号,冒号(`:`)也可省略。
- `obsoleted` 参数表示指定平台或语言从哪一版本开始废弃该声明。当一个声明被废弃后,它就从平台或语言中移除,不能再被使用。格式如下:
`obsoleted`: `版本号`
*版本号*由一至三个正整数构成,由句点分隔的。
- `message` 参数用来提供文本信息。当使用被弃用或者被废弃的声明时,编译器会抛出该信息作为警告或错误。格式如下:
`message`: `信息内容`
_信息内容_由一个字符串构成。
- `renamed` 参数用来提供文本信息,用以表示被重命名声明的新名字。当使用声明的旧名字时,编译器会报错并提示新名字。格式如下:
`renamed`: `新名字`
_新名字_由一个字符串构成。
你可以将带有 `renamed``unavailable` 参数的 `available` 特性应用于类型别名声明,如下所示,来表明框架和库发行版本之间的声明名称已经被更改。这个组合会导致声明已重命名的编译时错误。
```swift
// 首发版本
protocol MyProtocol {
// 这里是协议定义
}
```
```swift
// 后续版本重命名了 MyProtocol
protocol MyRenamedProtocol {
// 这里是协议定义
}
@available(*, unavailable, renamed:"MyRenamedProtocol")
typealias MyProtocol = MyRenamedProtocol
```
你可以在某个声明上使用多个 `available` 特性,以指定该声明在不同平台和 Swift 版本上的可用性。如果当前目标与 `available` 特性中指定的平台或语言版本不匹配时,该声明将会被忽略。如果你使用了多个 `available` 特性,则最终效果是平台和 Swift 可用性的组合。
如果 `available` 特性除了平台名称或者语言版本参数之外,只指定了一个 `introduced` 参数,那么可以使用以下简写语法代替:
@available(`平台名称` `版本号`, *)
@available(swift `版本号`)
`available` 特性的简写语法简洁的表示了多个平台的可用性。尽管这两种形式在功能上是相同的,但请尽可能地使用简写语法形式。
```swift
@available(iOS 10.0, macOS 10.12, *)
class MyClass {
// 这里是类定义
}
```
当需要同时指定 Swift 版本和平台可用性,需要使用一个单独的 `available` 特性来指明 Swift 版本,以及一个或者多个 `available` 特性来声明平台可用性。
```swift
@available(swift 3.0.2)
@available(macOS 10.12, *)
struct MyStruct {
// 这里是结构体定义
}
```
### `discardableResult` {#discardableresult}
该特性用于的函数或方法声明,以抑制编译器中函数或方法被调用而其返回值没有被使用时的警告。
### `dynamicCallable` {#dynamiccallable}
该特性用于类、结构体、枚举或协议,以将该类型的实例视为可调用的函数。该类型必须实现 `dynamicallyCall(withArguments:)``dynamicallyCall(withKeywordArguments:)` 方法之一,或两者同时实现。
你可以调用 `dynamicCallable` 特性的实例,就像是调用一个任意数量参数的函数。
```swift
@dynamicCallable
struct TelephoneExchange {
func dynamicallyCall(withArguments phoneNumber: [Int]) {
if phoneNumber == [4, 1, 1] {
print("Get Swift help on forums.swift.org")
} else {
print("Unrecognized number")
}
}
}
let dial = TelephoneExchange()
// 使用动态方法调用
dial(4, 1, 1)
// 打印“Get Swift help on forums.swift.org”
dial(8, 6, 7, 5, 3, 0, 9)
// 打印“Unrecognized number”
// 直接调用底层方法
dial.dynamicallyCall(withArguments: [4, 1, 1])
```
`dynamicallyCall(withArguments:)` 方法的声明必须至少有一个参数遵循 [`ExpressibleByArrayLiteral`](https://developer.apple.com/documentation/swift/expressiblebyarrayliteral) 协议,如 `[Int]`,而返回值类型可以是任意类型。
如果实现 `dynamicallyCall(withKeywordArguments:)` 方法,则可以在动态方法调用中包含标签。
```swift
@dynamicCallable
struct Repeater {
func dynamicallyCall(withKeywordArguments pairs: KeyValuePairs<String, Int>) -> String {
return pairs
.map { label, count in
repeatElement(label, count: count).joined(separator: " ")
}
.joined(separator: "\n")
}
}
let repeatLabels = Repeater()
print(repeatLabels(a: 1, b: 2, c: 3, b: 2, a: 1))
// a
// b b
// c c c
// b b
// a
```
`dynamicallyCall(withKeywordArguments:)` 方法声明必须只有一个遵循 [`ExpressibleByDictionaryLiteral`](https://developer.apple.com/documentation/swift/expressiblebydictionaryliteral) 协议的参数,返回值可以任意类型。参数的 [`Key`](https://developer.apple.com/documentation/swift/expressiblebydictionaryliteral/2294108-key) 必须遵循 [`ExpressibleByStringLiteral`](https://developer.apple.com/documentation/swift/expressiblebystringliteral) 协议。上述的示例使用 [`KeyValuePairs`](https://developer.apple.com/documentation/swift/keyvaluepairs) 作为参数类型,以便调用者可以传入重复的参数标签,`a``b` 在调用 `repeat`中多次使用。
如果你同时实现两种 `dynamicallyCall` 方法,则当在方法调用中包含关键字参数时,会调用 `dynamicallyCall(withKeywordArguments:)` 方法,否则调用 `dynamicallyCall(withArguments:)` 方法。
你只能调用参数和返回值与 `dynamicallyCall` 方法实现匹配的动态调用实例。在下面示例的调用无法编译,因为其 `dynamicallyCall(withArguments:)` 实现不接受 `KeyValuePairs<String, String>` 参数。
```swift
repeatLabels(a: "four") // Error
```
### `dynamicMemberLookup` {#dynamicmemberlookup}
该特性用于类、结构体、枚举或协议,让其能在运行时查找成员。该类型必须实现 `subscript(dynamicMemberLookup:)` 下标。
在显式成员表达式中,如果指定成员没有相应的声明,则该表达式被理解为对该类型的 `subscript(dynamicMemberLookup:)` 下标调用,将有关该成员的信息作为参数传递。下标接收参数既可以是键路径,也可以是成员名称字符串;如果你同时实现这两种方式的下标调用,那么以键路径参数方式为准。
`subscript(dynamicMemberLookup:)` 实现允许接收 [`KeyPath`](https://developer.apple.com/documentation/swift/keypath)[`WritableKeyPath`](https://developer.apple.com/documentation/swift/writablekeypath) 或 [`ReferenceWritableKeyPath`](https://developer.apple.com/documentation/swift/referencewritablekeypath) 类型的键路径参数。它可以使用遵循 [`ExpressibleByStringLiteral`](https://developer.apple.com/documentation/swift/expressiblebystringliteral) 协议的类型作为参数来接受成员名 -- 通常情况下是 `String`。下标返回值类型可以为任意类型。
按成员名进行的动态成员查找可用于围绕编译时无法进行类型检查的数据创建包装类型,例如在将其他语言的数据桥接到 `Swift` 时。例如:
```swift
@dynamicMemberLookup
struct DynamicStruct {
let dictionary = ["someDynamicMember": 325,
"someOtherMember": 787]
subscript(dynamicMember member: String) -> Int {
return dictionary[member] ?? 1054
}
}
let s = DynamicStruct()
// 使用动态成员查找
let dynamic = s.someDynamicMember
print(dynamic)
// 打印“325”
// 直接调用底层下标
let equivalent = s[dynamicMember: "someDynamicMember"]
print(dynamic == equivalent)
// 打印“true”
```
根据键路径来动态地查找成员,可用于创建一个包裹数据的包装类型,该类型支持在编译时期进行类型检查。例如:
```swift
struct Point { var x, y: Int }
@dynamicMemberLookup
struct PassthroughWrapper<Value> {
var value: Value
subscript<T>(dynamicMember member: KeyPath<Value, T>) -> T {
get { return value[keyPath: member] }
}
}
let point = Point(x: 381, y: 431)
let wrapper = PassthroughWrapper(value: point)
print(wrapper.x)
```
### `frozen` {#frozen}
针对枚举或者结构体的声明使用该特性,可以限制你对该类型的修改。它只有在编译迭代库时被允许使用。未来版本的库不能通过添加、删除或重新排序枚举的 case 或结构的存储实例属性来更改声明。在未冻结的类型上,这些操作都是允许的,但是他们破坏了冻结类型的 ABI 兼容性。
> 注意
> 当编译器不处于迭代库的模式,所有的结构体和枚举都是隐性冻结,并且该特性会被忽视。
在迭代库的模式中,与未冻结结构体和枚举的成员进行交互的代码在被编译时,允许它在不重新编译的情况下继续工作,即使在新版本的库中添加、删除或重新排序该类型的成员。编译器用类似运行时查找信息和添加间接层的技术使之可能。将一个枚举或者结构体标记为冻结将以放弃这种灵活性为代价来获取性能上的提升:未来版本的库只能对类型进行有限的更改,但编译器可以对与类型成员交互的代码进行额外的优化。
使用冻结类型,结构体存储属性的类型以及枚举 case 的关联值必须是 `public` 或使用 `usablefrominline` 特性标记。冻结结构体的属性不能有属性观察器,为存储实例属性提供初始值的表达式必须遵循与 `inlinable` 函数相同的限制,如 [`inlinable`](#inlinable) 中所述。
要在命令行上启用迭代库模式,请将 `-enable-library-evolution` 选项传递给 Swift 编译器。要在 Xcode 中支持它,则将生成设置 “Build Libraries for Distribution”`BUILD_LIBRARY_FOR_DISTRIBUTION`)设置为 Yes详情查看 [`Xcode 帮助文档`](https://help.apple.com/xcode/mac/current/#/dev04b3a04ba)。
针对冻结枚举的 switch 语法,不需要 `default` case就像 [`对未来枚举的 case 进行 switch`](./05_Statements.md#future-case)。在针对冻结枚举使用 switch 语法时包含 `default``@unknown default` case 将生成警告,因为该代码永远不会执行。
### `GKInspectable` {#gkinspectable}
应用此特性可将自定义 GameplayKit 组件属性公开到 SpriteKit 编辑器 UI。应用此特性同时表示应用了 `objc` 特性。
### `inlinable` {#inlinable}
该特性用于函数、方法、计算属性、下标、便利构造器或析构器的声明,以将该声明的实现公开为模块公开接口的一部分。编译器允许在调用处把 `inlinable` 标记的符号替换为符号实现的副本。
内联代码可以与任意模块中 `public` 访问级别的符号进行交互,同时可以与在相同模块中标记 `usableFromInline` 特性的 `internal` 访问级别的符号进行交互。内联代码不能与 `private``fileprivate` 级别的符号进行交互。
该特性不能用于嵌套在函数内的声明,也不能用于 `fileprivate``private` 访问级别的声明。在内联函数内定义的函数和闭包都是隐式内联的,即使他们不能标记该特性。
### `nonobjc` {#nonobjc}
针对方法、属性、下标、或构造器的声明使用该特性将覆盖隐式的 `objc` 特性。`nonobjc` 特性告诉编译器该声明不能在 Objective-C 代码中使用,即便它能在 Objective-C 中表示。
该特性用在扩展中,与在没有明确标记为 `objc` 特性的扩展中给每个成员添加该特性具有相同效果。
可以使用 `nonobjc` 特性解决标有 `objc` 的类中桥接方法的循环问题,该特性还允许对标有 `objc` 的类中的构造器和方法进行重载。
标有 `nonobjc` 特性的方法不能重写标有 `objc` 特性的方法。然而,标有 `objc` 特性的方法可以重写标有 `nonobjc` 特性的方法。同样,标有 `nonobjc` 特性的方法不能满足标有 `@objc` 特性的协议中的方法要求。
### `NSApplicationMain` {#nsapplicationmain}
在类上使用该特性表示该类是应用程序委托类。使用该特性与调用 `NSApplicationMain(_:_:)` 函数的效果相同。
如果你不想使用这个特性,可以提供一个 `main.swift` 文件,并在代码顶层调用 `NSApplicationMain(_:_:)` 函数,如下所示:
```swift
import AppKit
NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
```
### `NSCopying` {#nscopying}
该特性用于修饰一个类的存储型变量属性。该特性将使属性的设值方法使用传入值的`副本`进行赋值,这个值由传入值的 `copyWithZone(_:)` 方法返回,而不是传入值本身。该属性的类型必需符合 `NSCopying` 协议。
`NSCopying` 特性的行为与 Objective-C 中的 `copy` 属性特性相似。
### `NSManaged` {#nsmanaged}
该特性用于修饰 `NSManagedObject` 子类中的实例方法或存储型变量属性,表明它们的实现由 `Core Data` 在运行时基于相关实体描述动态提供。对于标记了 `NSManaged` 特性的属性,`Core Data` 也会在运行时为其提供存储。应用这个特性也意味着 `objc` 特性。
### `objc` {#objc}
该特性用于修饰任何可以在 Objective-C 中表示的声明。比如,非嵌套类、协议、非泛型枚举(仅限原始值为整型的枚举)、类的属性和方法(包括存取方法)、协议以及协议中的可选成员、构造器以及下标运算符。`objc` 特性告诉编译器这个声明可以在 Objective-C 代码中使用。
该特性用在扩展中,与在没有明确标记为 `nonobjc` 特性的扩展中给每个成员添加该特性具有相同效果。
编译器隐式地将 `objc` 特性添加到 Objective-C 中定义的任何类的子类。但是,子类不能是泛型的,并且不能继承于任何泛型类。你可以将 `objc` 特性显式添加到满足这些条件的子类,来指定其 Objective-C 名称,如下所述。添加了 `objc` 的协议不能继承于没有此特性的协议。
在以下情况中同样会隐式的添加 `objc` 特性:
- 父类有 `objc` 特性,且重写为子类的声明。
- 遵循带有 `objc` 特性协议的声明。
- 带有 `IBAction``IBSegueAction``IBOutlet``IBDesignable``IBInspectable``NSManaged``GKInspectable` 特性的声明。
如果你将 `objc` 特性应用于枚举,每一个枚举 case 都会以枚举名称和 case 名称组合的方式暴露在 Objective-C 代码中。实例名称的首字母大写。例如,在 Swift 枚举类型 `Planet` 中有一个名为 `Venus` 的 case该 case 暴露在 Objective-C 代码中时叫做 `PlanetVenus`
`objc` 特性可以接受一个可选的特性参数,由标识符构成。当你想把 `objc` 所修饰的实体以一个不同的名字暴露给 Objective-C 时,你就可以使用这个特性参数。你可以使用这个参数来命名类、枚举类型、枚举 case、协议、方法、存取方法以及构造器。如果你要指定类、协议或枚举在 Objective-C 下的名称,请在名称上包含三个字母的前缀,就像 [Objective-C 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html#//apple-ref/doc/uid/TP40011210) 中的 [约定](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Conventions/Conventions.html#//apple-ref/doc/uid/TP40011210-CH10-SW1)描述的一样。下面的例子把 `ExampleClass` 中的 `enabled` 属性的取值方法暴露给 Objective-C名字是 `isEnabled`,而不是它原来的属性名。
```swift
class ExampleClass: NSObject {
@objc var enabled: Bool {
@objc(isEnabled) get {
// 返回适当的值
}
}
}
```
更多相关信息,请参考 [把 Swift 导入 Objective-C](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_swift_into_objective-c)。
> 注意
> 具有 `objc` 特性的实参也会改变那个声明的运行时名称。在调用与 Objective-C 运行时交互的函数时,比如 [NSClassFromString](https://developer.apple.com/documentation/foundation/1395135-nsclassfromstring),以及在应用程序的 info.plist 文件中指定类名时,你会用到运行时名称。如果你通过传递实参的方式来指定名称,这个名称会作为 Objective-C 代码中的名称和运行时名称。如果你不使用这个实参,在 Objective-C 代码中使用的名称会与 Swift 代码中的名称匹配,并且运行时名称会遵循标准 Swift 编译器名称管理的惯例。
### `objcMembers` {#objcmembers}
该特性用于类声明,以将 `objc` 特性应用于该类、扩展、子类以及子类的扩展的所有 Objective-C 兼容成员。
大多数代码应该使用 `objc` 特性,以暴露所需的声明。如果需要暴露多个声明,可以将其分组到添加 `objc` 特性的扩展中。`objcMembers` 特性为大量使用 Objective-C 运行时的内省工具的库提供了便利。添加不必要的 `objc` 特性会增加二进制体积并影响性能。
### `propertyWrapper` {#propertywrapper}
在类、结构体或者枚举的声明时使用该特性,可以让其成为一个属性包装器。如果将该特性应用在一个类型上,将会创建一个与该类型同名的自定义特性。将这个新的特性用于类、结构体、枚举的属性,则可以通过包装器的实例封装对该属性的访问。局部和全局变量不能使用属性包装器。
包装器必须定义一个 `wrappedValue` 实例属性。该属性 _wrapped value_ 是该属性存取方法暴露的值。大多数时候,`wrappedValue` 是一个计算属性,但它可以是一个存储属性。包装器负责定义和管理其包装值所需的任何底层存储。编译器通过在包装属性的名称前加下划线(`_`)来为包装器的实例提供同步存储。例如,`someProperty` 的包装器存储为 `_someProperty`。包装器的同步存储具有 `private` 的访问控制级别。
拥有属性包装器的属性可以包含 `willSet``didSet` 闭包,但是不能重写编译器合成的 `get``set` 闭包。
Swift 为属性包装器的构造函数提供了两种形式的语法糖。可以在包装值的定义中使用赋值语法,将赋值语句右侧的表达式作为值传递给属性包装器构造函数中的 `wrappedValue` 参数。同样的,你也可以为包装器提供一些参数,这些参数将会传递给包装器的构造函数。就像下面的例子,`SomeStruct` 中,定义 `SomeWrapper` 的地方各自调用了对应的构造函数。
```swift
@propertyWrapper
struct SomeWrapper {
var wrappedValue: Int
var someValue: Double
init() {
self.wrappedValue = 100
self.someValue = 12.3
}
init(wrappedValue: Int) {
self.wrappedValue = wrappedValue
self.someValue = 45.6
}
init(wrappedValue value: Int, custom: Double) {
self.wrappedValue = value
self.someValue = custom
}
}
struct SomeStruct {
// 使用 init()
@SomeWrapper var a: Int
// 使用 init(wrappedValue:)
@SomeWrapper var b = 10
// 两个都是使用 init(wrappedValue:custom:)
@SomeWrapper(custom: 98.7) var c = 30
@SomeWrapper(wrappedValue: 30, custom: 98.7) var d
}
```
属性包装器中 _projected value_ 是它可以用来暴露额外功能的第二个值。属性包装器的作者负责确认其映射值的含义并定义公开映射值的接口。若要通过属性包装器来映射值,请在包装器的类型上定义 `projectedValue` 实例属性。编译器通过在包装属性的名称前面加上美元符号(`$`)来合成映射值的标识符。例如,`someProperty` 的映射值是 `$someProperty`。映射值具有与原始包装属性相同的访问控制级别。
```swift
@propertyWrapper
struct WrapperWithProjection {
var wrappedValue: Int
var projectedValue: SomeProjection {
return SomeProjection(wrapper: self)
}
}
struct SomeProjection {
var wrapper: WrapperWithProjection
}
struct SomeStruct {
@WrapperWithProjection var x = 123
}
let s = SomeStruct()
s.x // Int value
s.$x // SomeProjection value
s.$x.wrapper // WrapperWithProjection value
```
### `requires-stored-property-inits` {#requires-stored-property-inits}
该特性用于类声明,以要求类中所有存储属性提供默认值作为其定义的一部分。对于从中继承的任何类都推断出 `NSManagedObject` 特性。
### `testable` {#testable}
将此特性应用于 `import` 声明以导入该模块,并更改其访问控制以简化对该模块代码的测试。这样就能访问被导入模块中的任何标有 `internal` 访问级别修饰符的实体,犹如它们被标记了 `public` 访问级别修饰符。测试也可以访问使用 `internal` 或者 `public` 访问级别修饰符标记的类和类成员,就像它们是 `open` 访问修饰符声明的。被导入的模块必须以允许测试的方式编译。
### `UIApplicationMain` {#uiapplicationmain}
在类上使用该特性表示该类是应用程序委托类。使用该特性与调用 `UIApplicationMain` 函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
如果你不想使用这个特性,可以提供一个 `main.swift` 文件,并在代码顶层调用 `UIApplicationMain(_:_:_:_:)` 函数。比如,如果你的应用程序使用一个继承于 `UIApplication` 的自定义子类作为主要类,你可以调用 `UIApplicationMain(_:_:_:_:)` 函数而不是使用该特性。
### `usableFromInline` {#usablefrominline}
该特性用于函数、方法、计算属性、下标、构造器或析构器的声明,以在同一模块中允许该符号用于内联代码的声明。声明必须具有 `internal` 访问级别修饰符。被标记为 `usableFromInline` 的结构体或类它们属性的类型只能是被标记为 public 或者 `usableFromInline` 的类型。被标记为 `usableFromInline` 的枚举,它 case 的真实值或者关联类型只能是被标记为 public 或者 `usableFromInline` 的类型。
`public` 访问修饰符相同的是,该特性将声明公开为模块公共接口的一部分。区别于 `public`,编译器不允许在模块外部的代码通过名称引用 `usableFromInline` 标记的声明,即使导出了声明符号也无法引用。但是,模块外的代码仍然可以通过运行时与声明符号进行交互。
标记为 `inlinable` 特性的声明,在内联代码中可以隐式使用。虽然 `inlinable``usableFromInline` 可以用于 `internal` 声明,但这两者不能同时使用。
### `warn-unqualified-access` {#warn-unqualified-access}
该特性应用于顶级函数、实例方法、类方法或静态方法,以在没有前置限定符(例如模块名称、类型名称、实例变量或常量)的情况下使用该函数或方法时触发警告。使用该特性可以减少在同一作用域里访问的同名函数之间的歧义。
例如Swift 标准库包含 [`min(_:_:)`](https://developer.apple.com/documentation/swift/1538339-min/) 顶级函数和用于序列比较元素的 [`min()`](https://developer.apple.com/documentation/swift/sequence/1641174-min) 方法。序列方法声明使用了 `warn_unqualified_access`,以减少在 `Sequence` 扩展中使用它们的歧义。
### Interface Builder 使用的声明特性 {#declaration-attributes-used-by-interface-builder}
Interface Builder 特性是 Interface Builder 用来与 Xcode 同步的声明特性。Swift 提供了以下的 Interface Builder 特性:`IBAction``IBSegueAction``IBOutlet``IBDesignable`,以及 `IBInspectable`。这些特性与 Objective-C 中对应的特性在概念上是相同的。
`IBOutlet``IBInspectable` 用于修饰一个类的属性声明。`IBAction``IBSegueAction` 特性用于修饰一个类的方法声明,`IBDesignable` 用于修饰类的声明。
应用 `IBAction``IBSegueAction``IBOutlet``IBDesignable` 或者 `IBInspectable` 特性都意味着同时应用 `objc` 特性。
## 类型特性 {#type-attributes}
类型特性只能用于修饰类型。
### `autoclosure` {#autoclosure}
这个特性通过把表达式自动封装成无参数的闭包来延迟表达式的计算。它可以修饰类型为返回表达式结果类型的无参数函数类型的函数参数。关于如何使用 `autoclosure` 特性的例子,请参阅 [自动闭包](../02_language_guide/07_Closures.md#autoclosures) 和 [函数类型](./03_Types.md#function-type)。
### `convention` {#convention}
该特性用于修饰函数类型,它指出了函数调用的约定。
`convention` 特性总是与下面的参数之一一起出现。
- `swift` 参数用于表示一个 Swift 函数引用。这是 Swift 中函数值的标准调用约定。
- `block` 参数用于表示一个 Objective-C 兼容的块引用。函数值会作为一个块对象的引用,块是一种 `id` 兼容的 Objective-C 对象,其中嵌入了调用函数。调用函数使用 C 的调用约定。
- `c` 参数用于表示一个 C 函数引用。函数值没有上下文,不具备捕获功能,并且使用 C 的调用约定。
除了少数例外,当函数需要任何其他调用约定时,可以转换成任意调用约定的函数。非范型全局函数、不捕获任何局部变量的局部函数或不捕获任何局部变量的闭包可以转换为 C 调用约定。其余的 Swift 函数不能转换成 C 调用约定。一个 Objective-C 块调用约定的函数不能转换成 C 调用约定。
### `escaping` {#escaping}
在函数或者方法声明上使用该特性,它表示参数将不会被存储以供延迟执行。这将确保参数不会超出函数调用的生命周期。在使用 `escaping` 特性声明的函数类型中访问属性和方法时需要显式地使用 `self.`。关于如何使用 `escaping` 特性的例子,请参阅 [逃逸闭包](../02_language_guide/07_Closures.md#escaping-closures)。
## Switch Case 特性 {#switch-case-attributes}
你只能在 switch cases 语句中使用 switch case 特性。
### `unknown` {#unknown}
该特性用于 switch case用于没有匹配上代码编译时已知 case 的情况。有关如何使用 `unknown` 特性的示例,可参阅 [对未来枚举的 `case` 进行 `switch`](./05_Statements.md#future-case)。
> 特性语法
>
>
>
#### attribute {#attribute}
>
> *特性* → @ [特性名](#attribute-name) [特性参数子句](#atribute-argument-clause)<sub>可选</sub>
>
>
#### attribute-name {#attribute-name}
>
> *特性名* → [标识符](./02_Lexical_Structure.md#identifier)
>
>
#### atribute-argument-clause {#atribute-argument-clause}
>
> *特性参数子句* → **(** [均衡令牌列表](#balanced-tokens)<sub>可选</sub> **)**
>
>
#### attributes {#attributes}
>
> *特性列表* → [特性](#attribute) [特性列表](#attributes)<sub>可选</sub>
>
>
>
#### balanced-tokens {#balanced-tokens}
>
> *均衡令牌列表* → [均衡令牌](#balanced-token) [均衡令牌列表](#balanced-tokens)<sub>可选</sub>
>
>
#### balanced-token {#balanced-token}
>
> *均衡令牌* → **(** [均衡令牌列表](#balanced-tokens)<sub>可选</sub> **)**
>
> *均衡令牌* → **\[** [均衡令牌列表](#balanced-tokens)<sub>可选</sub> **\]**
>
> *均衡令牌* → **{** [均衡令牌列表](#balanced-tokens)<sub>可选</sub> **}**
>
> *均衡令牌* → 任意标识符,关键字,字面量或运算符
>
> *均衡令牌* → 任意标点除了 **(****)****[****]****{**,或 **}**
>

View File

@ -12,21 +12,21 @@ Swift 中的模式分为两类:一种能成功匹配任何类型的值,另
>
#### pattern {#pattern}
> *模式* → [*通配符模式*](#wildcard_pattern) [*类型注解*](03_Types.md#type-annotation)<sub>可选</sub>
> *模式* → [通配符模式](#wildcard-pattern) [类型注解](./03_Types.md#type-annotation)<sub>可选</sub>
>
> *模式* → [*标识符模式*](#identifier_pattern) [*类型注解*](03_Types.md#type-annotation)<sub>可选</sub>
> *模式* → [标识符模式](#identifier-pattern) [类型注解](./03_Types.md#type-annotation)<sub>可选</sub>
>
> *模式* → [*值绑定模式*](#value-binding-pattern)
> *模式* → [值绑定模式](#value-binding-pattern)
>
> *模式* → [*元组模式*](#tuple-pattern) [*类型注解*](03_Types.md#type-annotation)<sub>可选</sub>
> *模式* → [元组模式](#tuple-pattern) [类型注解](./03_Types.md#type-annotation)<sub>可选</sub>
>
> *模式* → [*枚举用例模式*](#enum-case-pattern)
> *模式* → [枚举用例模式](#enum-case-pattern)
>
> *模式* → [*可选模式*](#optional-pattern)
> *模式* → [可选模式](#optional-pattern)
>
> *模式* → [*类型转换模式*](#type-casting-pattern)
> *模式* → [类型转换模式](#type-casting-pattern)
>
> *模式* → [*表达式模式*](#expression-pattern)
> *模式* → [表达式模式](#expression-pattern)
>
## 通配符模式Wildcard Pattern {#wildcard-pattern}
@ -41,8 +41,7 @@ for _ in 1...3 {
> 通配符模式语法
>
#### wildcard-pattern {#wildcard-pattern}
> #### wildcard-pattern {#wildcard-pattern}
> *通配符模式* → **_**
>
@ -59,9 +58,8 @@ let someValue = 42
> 标识符模式语法
>
#### identifier-pattern {#identifier-pattern}
> *标识符模式* → [*标识符*](./02_Lexical_Structure.md#identifier)
> #### identifier-pattern {#identifier-pattern}
> *标识符模式* → [标识符](./02_Lexical_Structure.md#identifier)
>
## 值绑定模式Value-Binding Pattern {#value-binding-pattern}
@ -83,9 +81,8 @@ case let (x, y):
> 值绑定模式语法
>
#### value-binding-pattern {#value-binding-pattern}
> *值绑定模式***var** [*模式*](#pattern) | **let** [*模式*](#pattern)
> #### value-binding-pattern {#value-binding-pattern}
> *值绑定模式***var** [模式](#pattern) | **let** [模式](#pattern)
>
## 元组模式 {#tuple-pattern}
@ -113,29 +110,42 @@ let (a): Int = 2 // a: Int = 2
> 元组模式语法
>
#### tuple-pattern {#tuple-pattern}
> *元组模式***(** [*元组模式元素列表*](#tuple-pattern-element-list)<sub>可选</sub> **)**
> #### tuple-pattern {#tuple-pattern}
> *元组模式***(** [元组模式元素列表](#tuple-pattern-element-list)<sub>可选</sub> **)**
>
#### tuple-pattern-element-list {#tuple-pattern-element-list}
> *元组模式元素列表* → [*元组模式元素*](#tuple-pattern-element) | [*元组模式元素*](#tuple-pattern-element) **,** [*元组模式元素列表*](#tuple-pattern-element-list)
> *元组模式元素列表* → [元组模式元素](#tuple-pattern-element) | [元组模式元素](#tuple-pattern-element) **,** [元组模式元素列表](#tuple-pattern-element-list)
>
#### tuple-pattern-element {#tuple-pattern-element}
> *元组模式元素* → [*模式*](#pattern)
> #### tuple-pattern-element {#tuple-pattern-element}
> *元组模式元素* → [模式](#pattern)
>
## 枚举用例模式Enumeration Case Pattern {#enumeration-case-pattern}
*枚举用例模式*匹配现有的某个枚举类型的某个用例。枚举用例模式出现在 `switch` 语句中的 `case` 标签中,以及 `if``while``guard``for-in` 语句的 `case` 条件中。
如果你准备匹配的枚举用例有任何关联的值,则相应的枚举用例模式必须指定一个包含每个关联值元素的元组模式。关于使用 `switch` 语句来匹配包含关联值的枚举用例的例子,请参阅 [关联值](../chapter2/08_Enumerations.md#associated_values)。
如果你准备匹配的枚举用例有任何关联的值,则相应的枚举用例模式必须指定一个包含每个关联值元素的元组模式。关于使用 `switch` 语句来匹配包含关联值的枚举用例的例子,请参阅 [关联值](../02_language_guide/08_Enumerations.md#associated-values)。
枚举用例模式同样会匹配那些被包装成可选值的用例。简化的语法能将可选模式过滤掉。注意,由于 `Optional` 是枚举实现的,`.none``.some` 都会作为枚举类型的用例出现在 switch 中。
```swift
enum SomeEnum { case left, right }
let x: SomeEnum? = .left
switch x {
case .left:
print("Turn left")
case .right:
print("Turn right")
case nil:
print("Keep going straight")
}
// 打印 "Turn left"
```
> 枚举用例模式语法
>
#### enum-case-pattern {#enum-case-pattern}
> *枚举用例模式* → [*类型标识*](./03_Types.md#type-identifier)<sub>可选</sub> **.** [*枚举用例名*](./06_Declarations.md#enum-case-name) [*元组模式*](#tuple-pattern)<sub>可选</sub>
> #### enum-case-pattern {#enum-case-pattern}
> *枚举用例模式* → [类型标识](./03_Types.md#type-identifier)<sub>可选</sub> **.** [枚举用例名](./06_Declarations.md#enum-case-name) [元组模式](#tuple-pattern)<sub>可选</sub>
>
## 可选模式Optional Pattern {#optional-pattern}
@ -171,9 +181,8 @@ for case let number? in arrayOfOptinalInts {
> 可选模式语法
>
#### optional-pattern {#optional-pattern}
> *可选模式* → [*标识符模式*](./03_Types.md#type-identifier) **?**
> #### optional-pattern {#optional-pattern}
> *可选模式* → [标识符模式](./03_Types.md#type-identifier) **?**
>
## 类型转换模式Type-Casting Patterns {#type-casting-patterns}
@ -188,21 +197,18 @@ for case let number? in arrayOfOptinalInts {
`as` 模式仅当一个值的类型在运行时和 `as` 模式右边的指定类型一致,或者是其子类的情况下,才会匹配这个值。如果匹配成功,被匹配的值的类型被转换成 `as` 模式右边指定的类型。
关于使用 `switch` 语句配合 `is` 模式和 `as` 模式来匹配值的例子,请参阅 [Any 和 AnyObject 的类型转换](../chapter2/18_Type_Casting.md#type_casting_for_any_and_anyobject)。
关于使用 `switch` 语句配合 `is` 模式和 `as` 模式来匹配值的例子,请参阅 [Any 和 AnyObject 的类型转换](../02_language_guide/18_Type_Casting.md#type-casting-for-any-and-anyobject)。
> 类型转换模式语法
>
#### type-casting-pattern {#type-casting-pattern}
> *类型转换模式* → [*is 模式*](#is-pattern) | [*as 模式*](#as-pattern)
> #### type-casting-pattern {#type-casting-pattern}
> *类型转换模式* → [is 模式](#is-pattern) | [as 模式](#as-pattern)
>
#### is-pattern {#is-pattern}
> *is 模式***is** [*类型*](./03_Types.md#type)
> #### is-pattern {#is-pattern}
> *is 模式***is** [类型](./03_Types.md#type)
>
#### as-pattern {#as-pattern}
> *as 模式* → [*模式*](#pattern) **as** [*类型*](03_Types.md#type)
> #### as-pattern {#as-pattern}
> *as 模式* → [模式](#pattern) **as** [类型](./03_Types.md#type)
>
## 表达式模式Expression Pattern {#expression-pattern}
@ -242,7 +248,6 @@ default:
> 表达式模式语法
>
#### expression-pattern {#expression-pattern}
> *表达式模式* → [*表达式*](./04_Expressions.md#expression)
> #### expression-pattern {#expression-pattern}
> *表达式模式* → [表达式](./04_Expressions.md#expression)
>

View File

@ -2,7 +2,7 @@
本节涉及泛型类型、泛型函数以及泛型构造器的参数,包括形参和实参。声明泛型类型、函数或构造器时,须指定相应的类型参数。类型参数相当于一个占位符,当实例化泛型类型、调用泛型函数或泛型构造器时,就用具体的类型实参替代之。
关于 Swift 语言的泛型概述,请参阅 [泛型](../chapter2/22_Generics.md)。
关于 Swift 语言的泛型概述,请参阅 [泛型](../02_language_guide/22_Generics.md)。
## 泛型形参子句 {#generic-parameter}
*泛型形参子句*指定泛型类型或函数的类型形参,以及这些参数相关的约束和要求。泛型形参子句用尖括号(`<>`)包住,形式如下:
@ -49,51 +49,63 @@ simpleMax(3.14159, 2.71828) // T 被推断为 Double 类型
当然,替代类型形参的类型实参必须满足所有的约束和要求。
`where` 子句可以存在于包含类型参数的声明中,或作为声明的一部分,被嵌套另一个在含有类型参数的声明中。被嵌套的 `where` 子句依然可以指向包围它的声明中的类型参数,此时 `where` 子句需要满足的条件仅用于它被声明的地方。
如果外层的声明也有一个 `where` 子句,两个子句的条件都需要满足。下面的例子中,`startsWithZero()` 只有在 `Element` 同时满足 `SomeProtocol``Numeric` 才有效。
```swift
extension Collection where Element: SomeProtocol {
func startsWithZero() -> Bool where Element: Numeric {
return first == .zero
}
}
```
泛型函数或构造器可以重载,但在泛型形参子句中的类型形参必须有不同的约束或要求,抑或二者皆不同。当调用重载的泛型函数或构造器时,编译器会根据这些约束来决定调用哪个重载函数或构造器。
更多关于泛型 where 从句的信息和关于泛型函数声明的例子,可以看一看 [泛型 where 子句](../chapter2/22_Generics.md#where_clauses)。
更多关于泛型 where 从句的信息和关于泛型函数声明的例子,可以看一看 [泛型 where 子句](../02_language_guide/22_Generics.md#where-clauses)。
> 泛型形参子句语法
>
#### generic-parameter-clause {#generic-parameter-clause}
> *泛型形参子句***<** [*泛型形参列表*](#generic-parameter-list) [*约束子句*](#requirement-clause)<sub>可选</sub> **>**
> *泛型形参子句***<** [泛型形参列表](#generic-parameter-list) [约束子句](#requirement-clause)<sub>可选</sub> **>**
>
#### generic-parameter-list {#generic-parameter-list}
> *泛型形参列表* → [*泛形形参*](#generic-parameter) | [*泛形形参*](#generic-parameter) **,** [*泛型形参列表*](#generic-parameter-list)
> *泛型形参列表* → [泛形形参](#generic-parameter) | [泛形形参](#generic-parameter) **,** [泛型形参列表](#generic-parameter-list)
>
#### generic-parameter {#generic-parameter}
> *泛形形参* → [*类型名称*](./03_Types.md#type-name)
> *泛形形参* → [类型名称](./03_Types.md#type-name)
>
> *泛形形参* → [*类型名称*](./03_Types.md#type-name) **:** [*类型标识符*](./03_Types.md#type-identifier)
> *泛形形参* → [类型名称](./03_Types.md#type-name) **:** [类型标识符](./03_Types.md#type-identifier)
>
> *泛形形参* → [*类型名称*](./03_Types.md#type-name) **:** [*协议合成类型*](./03_Types.md#protocol-composition-type)
> *泛形形参* → [类型名称](./03_Types.md#type-name) **:** [协议合成类型](./03_Types.md#protocol-composition-type)
>
>
#### requirement-clause {#requirement-clause}
>
> *约束子句***where** [*约束列表*](#requirement-list)
> *约束子句***where** [约束列表](#requirement-list)
>
#### requirement-list {#requirement-list}
> *约束列表* → [*约束*](#requirement) | [*约束*](#requirement) **,** [*约束列表*](#requirement-list)
> *约束列表* → [约束](#requirement) | [约束](#requirement) **,** [约束列表](#requirement-list)
>
#### requirement {#requirement}
> *约束* → [*一致性约束*](#conformance-requirement) | [*同类型约束*](#same-type-requirement)
> *约束* → [一致性约束](#conformance-requirement) | [同类型约束](#same-type-requirement)
>
>
#### conformance-requirement {#conformance-requirement}
>
> *一致性约束* → [*类型标识符*](./03_Types.md#type-identifier) **:** [*类型标识符*](./03_Types.md#type-identifier)
> *一致性约束* → [类型标识符](./03_Types.md#type-identifier) **:** [类型标识符](./03_Types.md#type-identifier)
>
> *一致性约束* → [*类型标识符*](./03_Types.md#type-identifier) **:** [*协议合成类型*](./03_Types.md#protocol-composition-type)
> *一致性约束* → [类型标识符](./03_Types.md#type-identifier) **:** [协议合成类型](./03_Types.md#protocol-composition-type)
>
#### same-type-requirement {#same-type-requirement}
> *同类型约束* → [*类型标识符*](./03_Types.md#type-identifier) **==** [*类型*](./03_Types.md#type)
> *同类型约束* → [类型标识符](./03_Types.md#type-identifier) **==** [类型](./03_Types.md#type)
>
## 泛型实参子句 {#generic-argument}
@ -118,19 +130,19 @@ struct Dictionary<Key: Hashable, Value>: CollectionType, DictionaryLiteralConver
let arrayOfArrays: Array<Array<Int>> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
```
如 [泛型形参子句](#generic_parameter) 所述,不能用泛型实参子句来指定泛型函数或构造器的类型实参。
如 [泛型形参子句](#generic-parameter) 所述,不能用泛型实参子句来指定泛型函数或构造器的类型实参。
> 泛型实参子句语法
>
#### generic-argument-clause {#generic-argument-clause}
> *泛型实参子句***<** [*泛型实参列表*](#generic-argument-list) **>**
> *泛型实参子句***<** [泛型实参列表](#generic-argument-list) **>**
>
#### generic-argument-list {#generic-argument-list}
> *泛型实参列表* → [*泛型实参*](#generic-argument) | [*泛型实参*](#generic-argument) **,** [*泛型实参列表*](#generic-argument-list)
> *泛型实参列表* → [泛型实参](#generic-argument) | [泛型实参](#generic-argument) **,** [泛型实参列表](#generic-argument-list)
>
#### generic-argument {#generic-argument}
> *泛型实参* → [*类型*](./03_Types.md#type)
> *泛型实参* → [类型](./03_Types.md#type)
>

View File

@ -1,3 +1,3 @@
# Swift 教程
# Swift 语言参考
本章描述了 Swift 的语言参考。

View File

@ -0,0 +1,278 @@
# Swift 文档修订历史
### 2020-02-05
* 更新至 Swift 5.2。
* 在 [特殊名称方法](../03_language_reference/06_Declarations.md#methods-with-special-names) 章节中新增了有关让类、结构体和枚举的实例作为函数调用语法糖的内容。
* 更新 [下标选项](../02_language_guide/12_Subscripts.md#subscript-options) 章节,现在下标支持形参默认值。
* 更新 [自身类型](../03_language_reference/03_Types.md#self-type-h) 章节,现在 `Self` 可以在更多上下文中使用。
### 2019-09-10
* 更新至 Swift 5.1。
* 在 [不透明类型](../02_language_guide/23_Opaque_Types.md) 篇章中新增了有关函数返回值遵循指定协议,而不需要提供指定返回类型的内容。
* 在 [属性包装器](../02_language_guide/10_Properties.md#property-wrappers) 章节中新增了有关属性包装器的内容。
* 在 [冻结](../03_language_reference/07_Attributes.md#frozen) 章节中新增了有关因库演变而需要的枚举和结构体冻结。
* 新增 [隐式返回的函数](../02_language_guide/06_Functions.md#functions-with-an-implicit-return) 和 [简化 Getter 声明](../02_language_guide/10_Properties.md#shorthand-getter-declaration) 章节,其中包含函数省略 `return` 的内容。
* 在 [类型下标](../02_language_guide/12_Subscripts.md#type-subscripts) 章节中新增了有关在类型中使用下标的内容。
* 更新 [枚举 Case 模式匹配](../03_language_reference/08_Patterns.md#enumeration-case-pattern) 章节,现在枚举 case 模式匹配支持匹配可选值。
* 更新 [结构体的逐一成员构造器](../02_language_guide/14_Initialization.md#memberwise-initializers-for-structure-types) 章节,现在逐一成员构造器支持在属性有默认值时省略形参。
* 在 [动态查找成员](../03_language_reference/07_Attributes.md#dynamicmemberlookup) 章节中新增了有关在运行时用 key path 查找动态成员的内容。
* 在 [条件编译代码块](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 中的目标环境里添加了 `macCatalyst`
* 更新 [自身类型](../03_language_reference/03_Types.md#self-type-h) 章节,现在 `Self` 可以指向当前类,结构体或者枚举声明时的类型。
### 2019-03-25
* 更新至 Swift 5。
* 新增 [拓展字符串分隔符](../02_language_guide/03_Strings_and_Characters.md#extended-string-delimiters) 章节。更新 [字符串字面量](../03_language_reference/02_Lexical_Structure.md#string-literal) 章节,拓展有关字符串分隔符的内容。
* 新增 [动态调用](../03_language_reference/07_Attributes.md#dynamiccallable) 章节,其中包含使用 `dynamicCallable` 属性动态调用实例作为函数的内容。
* 新增 [unknown](../03_language_reference/07_Attributes.md#unknown) 和 [未来枚举匹配](../03_language_reference/05_Statements.md#future-case) 章节,其中包含了使用 `unknown` 来处理未来枚举可能发生改变的情形。
* 在 [Key-Path 表达式](../03_language_reference/04_Expressions.md#key-path-expression) 章节新增了有关标示 key path (\\.self) 的内容。
* 在 [可选编译块](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节新增了有关小于比较符 `<` 的内容。
### 2018-09-17
* 更新至 Swift 4.2。
* 在 [遍历枚举情形](../02_language_guide/08_Enumerations.md#iterating-over-enumeration-cases) 章节新增了有关访问所有枚举情形的内容。
* 在 [编译诊断](../03_language_reference/05_Statements.md#compile-time-diagnostic-statement) 章节新增了有关 `#error``#warning` 的内容。
* 在 [属性声明](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `inlinable``usableFromInline` 属性的内容。
* 在 [属性声明](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `requires-stored-property-inits``warn-unqualified-access` 属性的内容。
* 在 [可选编译块](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节新增了有关如何根据 Swift 编译器版本对代码进行对应编译处理的内容。
* 在 [字面量语法](../03_language_reference/04_Expressions.md#literal-expression) 章节新增了有关 `#dsohandle` 的内容。
### 2018-03-29
* 更新至 Swift 4.1。
* 在 [等价运算符](../02_language_guide/27_Advanced_Operators.md#equivalence-operators) 章节新增了有关等价运算符的合成实现的内容。
* 在 [声明](../03_language_reference/06_Declarations.md) 篇章中 [声明拓展](../03_language_reference/06_Declarations.md#extension-declaration) 章节和 [协议](../02_language_guide/21_Protocols.md) 篇章中 [有条件地遵循协议](../02_language_guide/21_Protocols.md#Conditionally-Conforming-to-a-Protocol) 章节新增了有关协议有条件遵循的内容。
* 在 [关联类型约束中使用协议](../02_language_guide/22_Generics.md#using-a-protocol-in-its-associated-types-constraints) 章节中新增了有关递归协议约束的内容。
* 在 [条件编译块](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节中新增了有关 `canImport()``targetEnvironment()` 平台条件的内容。
### 2017-12-04
* 更新至 Swift 4.0.3。
* 更新 [Key-Path 表达式](../03_language_reference/04_Expressions.md#key-path-expression) 章节,现在 key path 支持下标子路径。
### 2017-09-19
* 更新至 Swift 4.0。
* 在 [内存安全](../02_language_guide/25_Memory_Safety.md) 章节新增了有关内存互斥访问的内容。
* 新增 [带有泛型 Where 子句联类型](../02_language_guide/22_Generics.md#associated-types-with-a-generic-where-clause) 章节,现在可以使用泛型 `where` 子句约束关联类型。
* 在 [字符串和字符](../02_language_guide/03_Strings_and_Characters.md) 篇章中 [字面量](../02_language_guide/03_Strings_and_Characters.md#string-literals) 章节以及 [词法结构](../03_language_reference/02_Lexical_Structure.md) 篇章的 [字符串字面量](../03_language_reference/02_Lexical_Structure.md#string-literal) 章节中新增了有关多行字符串字面量的内容。
* 更新 [声明属性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 中 `objc` 属性的讨论,现在该属性会在更少的位置被推断出来。
* 新增 [范型下标](../02_language_guide/22_Generics.md#generic-subscripts) 章节,现在下标也支持范型特性了。
* 更新 [协议](../02_language_guide/21_Protocols.md) 篇章中 [协议组合](../02_language_guide/21_Protocols.md#protocol-composition) 章节和 [类型](../03_language_reference/03_Types.md) 篇章中 [协议组合类型](../03_language_reference/03_Types.md#protocol-composition-type-h) 章节的讨论,现在协议组合类型支持进行父类约束了。
* 更新 [拓展声明](../03_language_reference/06_Declarations.md#extension-declaration) 中有关协议扩展的讨论,现在它们不支持 `final` 特性了。
* 在 [断言和前置条件](../02_language_guide/01_The_Basics.md#assertions-and-preconditions) 章节中新增了部分前置条件和致命错误的内容。
### 2017-03-27
* 更新至 Swift 3.1。
* 新增 [范型 Where 子句扩展](../02_language_guide/22_Generics.md#extensions-with-a-generic-where-clause) 章节,包含需要的扩展内容。
* 在 [For-In 循环](../02_language_guide/05_Control_Flow.md#for-in-loops) 章节中新增了区间迭代的例子。
* 在 [可失败构造器](../02_language_guide/14_Initialization.md#failable-initializers) 章节中新增了可失败数值转换的例子。
* 在 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关使用 Swift 语言版本的 `available` 特性的内容 。
* 更新 [函数类型](../03_language_reference/03_Types.md#function-type-h) 章节中的讨论,注意在写函数类型时不允许使用参数标签。
* 更新 [条件编译块](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节中的 Swift 语言版本号的讨论,现在可以使用可选的补丁版本号。
* 更新 [函数类型](../03_language_reference/03_Types.md#function-type-h) 章节的讨论,现在 Swift 区分了采用多参数的函数和采用元组类型的单个参数的函数。
* 在 [表达式](../03_language_reference/04_Expressions.md) 篇章中删除了动态表达式的章节,现在 `type(of:)` 是 Swift 标准库函数。
### 2016-10-27
* 更新至 Swift 3.0.1。
* 更新 [自动引用计数](../02_language_guide/24_Automatic_Reference_Counting.md) 章节中有关 weak 和 unowned 引用的讨论。
* 在 [声明标识符](../03_language_reference/06_Declarations.md#declaration-modifiers) 章节中新增了有关新的标识符 `unowned``unowend(safe)``unowned(unsafe)` 的内容。
* 在 [Any 和 AnyObject 的类型转换](../02_language_guide/18_Type_Casting.md#type-casting-for-any-and-anyobject) 章节中新增了一处说明,有关使用类型 `Any` 作为可选值。
* 更新 [表达式](../03_language_reference/04_Expressions.md) 章节,把括号表达式和元组表达式的描述分开。
### 2016-09-13
* 更新至 Swift 3.0。
* 更新 [函数](../02_language_guide/06_Functions.md) 篇章和 [函数声明](../03_language_reference/06_Declarations.md#function-declaration) 章节中有关函数的讨论,所有函数参数默认都有函数标签。
* 更新 [高级操作符](../02_language_guide/27_Advanced_Operators.md) 篇章中有关操作符的讨论,现在你可以作为类型函数来实现,替代之前的全局函数实现方式。
* 在 [访问控制](../02_language_guide/26_Access_Control.md) 章节中新增有关对新的访问级别描述符 `open``fileprivate` 的内容。
* 更新 [函数声明](../03_language_reference/06_Declarations.md#function-declaration) 章节中有关 `inout` 的讨论,注意它现在出现在参数类型的前面,而不是在参数名称的前面。
* 更新 [逃逸闭包](../02_language_guide/07_Closures.md#escaping-closures) 和 [自动闭包](../02_language_guide/07_Closures.md#autoclosures) 章节还有 [属性](../03_language_reference/07_Attributes.md) 篇章中有关 `@noescape``@autoclosure` 的讨论,现在他们是类型属性,而不是定义属性。
* 在 [高级操作符](../02_language_guide/27_Advanced_Operators.md) 篇章中 [自定义中缀操作符的优先级](./02_language_guide/27_Advanced_Operators.md#precedence-and-associativity-for-custom-infix-operators) 章节和 [定义](../03_language_reference/06_Declarations.md) 篇章中 [优先级组声明](../03_language_reference/06_Declarations.md#precedence-group-declaration-modifiers) 章节中新增了有关操作符优先级组的内容。
* 更新一些讨论,使用 macOS 替换掉 OS X Error 替换掉 ErrorProtocol。更新一些协议名称比如使用 ExpressibleByStringLiteral 替换掉 StringLiteralConvertible。
* 更新 [泛型](../02_language_guide/22_Generics.md) 篇章中 [泛型 Where 语句](../02_language_guide/22_Generics.md#extensions-with-a-generic-where-clause) 章节和 [泛型形参和实参](../03_language_reference/09_Generic_Parameters_and_Arguments.md) 篇章的讨论,现在泛型的 where 语句写在一个声明的最后。
* 更新 [逃逸闭包](../02_language_guide/07_Closures.md#escaping-closures) 章节中的讨论,现在闭包默认为非逃逸的。
* 更新 [基础部分](../02_language_guide/01_The_Basics.md) 篇章中 [可选绑定](../02_language_guide/01_The_Basics.md#optional-binding) 章节和 [语句](../03_language_reference/05_Statements.md) 篇章中 [While 语句](../03_language_reference/05_Statements.md#while-statement) 章节中的讨论,现在 if`while``guard` 语句使用逗号分隔条件列表,不需要使用 `where` 语句。
* 在 [控制流](../02_language_guide/05_Control_Flow.md) 篇章中 [Switch](../02_language_guide/05_Control_Flow.md#switch) 章节和 [语句](../03_language_reference/05_Statements.md) 篇章中 [Switch 语句](../03_language_reference/05_Statements.md#switch-statement) 章节中新增了 switch cases 可以使用多模式的内容。
* 更新 [函数类型](../03_language_reference/03_Types.md#function-type-h) 章节有关现在函数参数标签不包含在函数类型中的讨论。
* 更新 [协议](../02_language_guide/21_Protocols.md) 篇章中 [协议组合](../02_language_guide/21_Protocols.md#protocol-composition) 章节和 [类型](../03_language_reference/03_Types.md) 篇章中 [协议组合类型](../03_language_reference/03_Types.md#protocol-composition-type-h) 章节中有关使用新的 Protocol1 & Protocol2 语法的内容。
* 更新动态类型表达式章节中使用新的 `type(of:)` 表达式的讨论。
* 更新 [行控制表达式](../03_language_reference/05_Statements.md#line-control-statement) 章节中使用 `#sourceLocation(file:line:)` 表达式的讨论。
* 更新 [永不返回函数](../03_language_reference/06_Declarations.md#functions-that-never-return) 章节中使用 新的 `Never` 类型的讨论。
* 在 [字面量表达式](../03_language_reference/04_Expressions.md#literal-expression) 章节中新增了有关 `playground` 字面量的内容。
* 更新 [In-Out 参数](../03_language_reference/06_Declarations.md#in-out-parameters) 章节,标明只有非逃逸闭包能捕获 `in-out` 参数。
* 更新 [默认参数值](../02_language_guide/06_Functions.md#default-parameter-values) 章节,现在默认参数不能在调用时候重新排序。
* 更新 [属性](../03_language_reference/07_Attributes.md) 篇章中有关属性参数使用分号的说明。
* 在 [重新抛出函数和方法](../03_language_reference/06_Declarations.md#rethrowing-functions-and-methods) 章节中新增了有关在 catch 代码块中抛出错误的重新抛出函数的内容。
* 在 [Selector 表达式](../03_language_reference/04_Expressions.md#selector-expression7) 章节中新增了中有关访问 Objective-C 中 Selector 的 getter 和 setter 的内容。
* 在 [类型别名声明](../03_language_reference/06_Declarations.md#type-alias-declaration) 章节中中新增了有关泛型类型别名和在协议内使用类型别名的内容。
* 更新 [函数类型](../03_language_reference/03_Types.md#function-type-h) 章节中有关函数类型的讨论,标明函数类型作为参数类型必须使用括号包裹。
* 更新 [属性](../03_language_reference/07_Attributes.md) 篇章,标明 `@IBAction``@IBOutlet``@NSManaged` 隐式含有 `@objc` 属性。
* 在 [声明属性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `@GKInspectable` 的内容。
* 更新 [可选协议要求](../02_language_guide/21_Protocols.md#optional-protocol-requirements) 章节中有关只能在与 `Objective-C` 交互的代码中才能使用可选协议要求的内容。
* 删除 [函数声明](../03_language_reference/06_Declarations.md#function-declaration) 章节中有关显式使用 `let` 关键字作为函数参数的内容。
* 删除 [语句](../03_language_reference/05_Statements.md) 章节中有关 `Boolean` 协议的内容, 现在这个协议已经被 Swift 标准库删除。
* 更正 [声明属性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@NSApplicationMain` 协议的内容。
### 2016-03-21
* 更新至 Swift 2.2。
* 在 [编译配置语句](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节新增了中有关如何根据 Swift 版本进行条件编译。
* 在 [显示成员表达式](../03_language_reference/04_Expressions.md#explicit-member-expression) 章节中新增了有关如何区分只有参数名不同的方法和构造器的内容。
* 在 [选择器表达式](../03_language_reference/04_Expressions.md#selector-expression7) 章节中新增了了针对 Objective-C 选择器的 `#selector` 语法。
* 更新 [关联类型](../02_language_guide/22_Generics.md#associated-types) 和 [协议关联类型声明](../03_language_reference/06_Declarations.md#protocol-associated-type-declaration) 章节中有关使用 `associatedtype` 关键词修饰关联类型的讨论。
* 更新 [可失败构造器](../02_language_guide/14_Initialization.md#failable-initializers) 章节中有关当构造器在实例完全初始化之前返回 `nil` 的相关内容。
* 在 [比较运算符](../02_language_guide/02_Basic_Operators.md#comparison-operators) 章节中新增了比较元组的内容。
* 在 [关键字和标点符号](../03_language_reference/02_Lexical_Structure.md#keywords-and-punctuation) 章节中新增了使用关键字作为外部参数名的内容。
* 更新 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@objc` 特性的讨论,并指出枚举和枚举用例。
* 更新 [操作符](../03_language_reference/02_Lexical_Structure.md#operator) 章节中对于自定义运算符的包含了 `.` 的讨论。
* 在 [重新抛出错误的函数和方法](../03_language_reference/06_Declarations.md#rethrowing-functions-and-methods) 章节中新增了一处说明,重新抛出错误函数不能直接抛出错误。
* 在 [属性观察器](../02_language_guide/10_Properties.md#property-observers) 章节中新增了一处说明,当作为 in-out 参数传递属性时,属性观察器的调用行为。
* 在 [Swift 初见](../01_welcome_to_swift/03_a_swift_tour.md) 篇章中新增了错误处理的章节。
* 更新 [弱引用](../02_language_guide/24_Automatic_Reference_Counting.md#weak-references) 章节中的图片用以更清楚的展示重新分配过程。
* 删除 C 语言风格的 `for` 循环,`++` 前缀和后缀运算符,以及 `--` 前缀和后缀运算符。
* 删除对变量函数参数和柯里化函数的特殊语法的讨论。
### 2015-10-20
* 更新至 Swift 2.1。
* 更新 [字符串插值](../02_language_guide/03_Strings_and_Characters.md#string-interpolation) 和 [字符串字面量](../03_language_reference/02_Lexical_Structure.md#string-literal) 章节,现在字符串插值可包含字符串字面量。
* 在 [逃逸闭包](../02_language_guide/07_Closures.md#escaping-closures) 章节中新增了有关 `@noescape` 属性的相关内容。
* 更新 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 和 [编译配置语句](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节中与 tvOS 相关的内容。
* 在 [In-Out 参数](../03_language_reference/06_Declarations.md#in-out-parameters) 章节中新增了与 in-out 参数行为相关的内容。
* 在 [捕获列表](../03_language_reference/04_Expressions.md#capture-lists) 章节新增了有关指定闭包捕获列表被捕获时捕获值的相关内容。
* 更新 [可选链式调用访问属性](../02_language_guide/16_Optional_Chaining.md#accessing-properties-through-optional-chaining) 章节,阐明了如何通过可选链式调用进行赋值。
* 改进 [自动闭包](../02_language_guide/07_Closures.md#autoclosures) 章节中对自闭包的讨论。
* 在 [Swift 初见](../01_welcome_to_swift/03_a_swift_tour.md) 篇章中新增了一个使用 `??` 操作符的例子。
### 2015-09-16
* 更新至 Swift 2.0。
* 在 [错误处理](../02_language_guide/17_Error_Handling.md) 篇章中新增了有关错误处理的相关内容,包括 [Do 语句](../03_language_reference/05_Statements.md#do-statement)、 [Throw 语句](../03_language_reference/05_Statements.md#throw-statement)、 [Defer 语句](../03_language_reference/05_Statements.md##defer-statements) 以及 [try 运算符](../03_language_reference/04_Expressions.md#try-operator)。
* 更新 [错误表示和抛出](../02_language_guide/17_Error_Handling.md#representing-and-throwing-errors) 章节,现在所有类型都可以遵循 `ErrorType` 协议了。
* 在 [将错误装换成可选值](../02_language_guide/17_Error_Handling.md#converting-errors-to-optional-values) 篇章增加了 `try?` 关键字相关内容。
* 在 [枚举](../02_language_guide/08_Enumerations.md) 篇章的 [递归枚举](../02_language_guide/08_Enumerations.md#recursive-enumerations) 章节以及以及 [声明](../03_language_reference/06_Declarations.md) 篇章的 [任意类型用例的枚举](../03_language_reference/06_Declarations.md#enumerations-with-cases-of-any-type) 章节中新增了递归枚举相关内容。
* 在 [控制流](../02_language_guide/05_Control_Flow.md) 篇章的 [API 可用性检查](../02_language_guide/05_Control_Flow.md#checking-api-availability) 章节和 [语句](../03_language_reference/05_Statements.md) 篇章的 [可用性条件](../03_language_reference/05_Statements.md#availability-condition) 章节中新增了有关 API 可用性检查相关的内容。
* 在 [控制流](../02_language_guide/05_Control_Flow.md) 篇章的 [尽早退出](../02_language_guide/05_Control_Flow.md#early-exit) 章节和 [语句](../03_language_reference/05_Statements.md) 篇章的 [Guard 语句](../03_language_reference/05_Statements.md#guard-statement) 章节新增了与 `guard` 语句相关的内容。
* 在 [协议](../02_language_guide/21_Protocols.md) 篇章中 [协议扩展](../02_language_guide/21_Protocols.md#protocol-extensions) 章节中新增了有关协议扩展的内容。
* 在 [访问控制](../02_language_guide/26_Access_Control.md) 篇章的 [单元测试 target 的访问级别](../02_language_guide/26_Access_Control.md#access-levels-for-unit-test-targets) 章节中新增了有关单元测试访问控制相关的内容。
* 在 [模式](../03_language_reference/08_Patterns.md) 篇章的 [可选模式](../03_language_reference/08_Patterns.md#optional-pattern) 章节中新增了可选模式相关内容。
* 更新 [Repeat-While](../02_language_guide/05_Control_Flow.md#repeat-while) 章节中有关 `repeat-while` 循环相关的内容。
* 更新 [字符串和字符](../02_language_guide/03_Strings_and_Characters.md) 章节,现在 `String` 类型在 Swift 标准库中不再遵循 `CollectionType` 协议。
* 在 [常量与变量打印](../02_language_guide/01_The_Basics.md#printing) 章节中新增了新 Swift 标准库中有关 `print(-:separator:terminator) ` 相关内容。
* 在 [枚举](../02_language_guide/08_Enumerations.md) 篇章的 [原始值的隐式赋值](../02_language_guide/08_Enumerations.md#implicitly-assigned-raw-values) 章节和 [声明](../03_language_reference/06_Declarations.md) 篇章的 [包含原始值类型的枚举](../03_language_reference/06_Declarations.md#enumerations-with-cases-of-a-raw-value-type) 章节中新增了有关包含 `String` 原始值的枚举用例的行为相关内容。
* 在 [自动闭包](../02_language_guide/07_Closures.md#autoclosures) 章节中新增了有关 `@autoclosure` 特性的相关内容,包括它的 `@autoclosure(escaping)` 形式。
* 更新 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@avaliable``warn-unused-result` 特性的相关内容。
* 更新 [类型特性](../03_language_reference/07_Attributes.md#type-attributes) 章节中有关 `@convention` 特性的相关内容。
* 在 [可选绑定](../02_language_guide/01_The_Basics.md#optional-binding) 章节中新增了有关使用 `where` 子句进行多可选绑定的相关内容。
* 在 [字符串字面量](../03_language_reference/02_Lexical_Structure.md#string-literal) 章节中新增了有关在编译时使用 `+` 运算符拼接字符串字面量的相关内容。
* 在 [元类型](../03_language_reference/03_Types.md#metatype-type-h) 章节中新增了有关元类型值的比较和使用它们通过构造器表达式构造实例相关内容。
* 在 [断言调试](../02_language_guide/01_The_Basics.md#debugging-with-assertions) 章节中新增了一处说明,有关用户定义断言何时会失效。
* 更新 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中对 `@NSManaged` 特性的讨论,现在这个特性可以被应用到一个确定实例方法。
* 更新 [可变参数](../02_language_guide/06_Functions.md#variadic-parameters) 章节,现在可变参数可以声明在函数参数列表的任意位置中。
* 在 [重写可失败构造器](../02_language_guide/14_Initialization.md#overriding-a-failable-initializer) 章节中新增了有关非可失败构造器相当于一个可失败构造器通过父类构造器的结果进行强制拆包的相关内容。
* 在 [任意类型用例的枚举](../03_language_reference/06_Declarations.md#enumerations-with-cases-of-any-type) 章节中新增了有关枚举用例作为函数的内容。
* 在 [构造器表达式](../03_language_reference/04_Expressions.md#initializer-expression) 章节中新增了有关显式引用一个构造器相关内容。
* 在 [编译控制语句](../03_language_reference/05_Statements.md#compiler-control-statements) 章节中新增了有关编译内容以及行控制语句相关内容。
* 在 [元类型](../03_language_reference/03_Types.md#metatype-type-h) 章节新增了一处说明,有关如何从元类型值中构造类实例相关内容。
* 在 [弱引用](../02_language_guide/24_Automatic_Reference_Counting.md#weak-references) 章节新增了一处说明,有关弱引用作为缓存所存在的不足。
* 更新 [类型特性](../02_language_guide/10_Properties.md#type-properties) 章节,提到了存储型特性其实是懒加载。
* 更新 [捕获类型](../02_language_guide/07_Closures.md#capturing-values) 章节,阐明了变量和常量在闭包中如何被捕获。
* 更新 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节,用以描述何时在类中使用 `@objc` 关键字。
* 在 [错误处理](../02_language_guide/17_Error_Handling.md#handling-errors) 章节中新增了一处说明,有关执行 `throw` 语句的性能。在 [Do 语句](../03_language_reference/05_Statements.md#do-statement) 章节的 do 语句部分也新增了类似内容。
* 更新 [类型特性](../02_language_guide/10_Properties.md#type-properties) 章节中有关类、结构体和枚举的存储型和计算型特性相关的内容。
* 更新 [Break 语句](../03_language_reference/05_Statements.md#break-statement) 章节中有关带标签的 break 语句相关内容。
* 在 [属性观察器](../02_language_guide/10_Properties.md#property-observers) 章节更新了一处说明,用来明确 `willSet``didSet` 观察器的行为。
* 在 [访问级别](../02_language_guide/26_Access_Control.md#access-levels) 章节新增了有关 `private` 作用域的相关内容说明。
* 在 [弱引用](../02_language_guide/24_Automatic_Reference_Counting.md#weak-references) 章节新增了有关弱应用在垃圾回收系统和 ARC 之间的区别的说明。
* 更新 [字符串字面量中特殊字符](../02_language_guide/03_Strings_and_Characters.md#special-characters-in-string-literals) 章节,对 Unicode 标量更精确定义。
### 2015-04-08
* 更新至 Swift 1.2。
* Swift 现在自身提供了一个 `Set` 集合类型,更多内容,请看 [Sets](../02_language_guide/04_Collection_Types.md#sets) 。
* `@autoclosure` 现在是一个参数声明的属性,而不是参数类型的属性。这里还有一个新的参数声明属性 `@noescape`。更多内容,请看 [属性声明](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 。
* 对于类型属性和方法现在可以使用 `static` 关键字作为声明描述符,更多内容,请看 [类型变量属性](../03_language_reference/06_Declarations.md#type-variable-properties)。
* Swift 现在包含一个 `as?``as!` 的向下可失败类型转换运算符。更多内容,请看 [协议遵循性检查](../02_language_guide/21_Protocols.md#checking-for-protocol-conformance)。
* 新增 [字符串索引](../02_language_guide/03_Strings_and_Characters.md#string-indices) 的新指导章节。
* 在 [溢出运算符](../02_language_guide/27_Advanced_Operators.md#overflow-operators) 一节中删除了溢出除运算符(`&/`)和求余溢出运算符(`&%`)。
* 更新常量和常量属性在声明和构造时的规则,更多内容,请看 [常量声明](../03_language_reference/06_Declarations.md#constant-declaration) 。
* 更新字符串字面量中 Unicode 标量集的定义,请看 [字符串字面量中的特殊字符](../02_language_guide/03_Strings_and_Characters.md#special-characters-in-string-literals) 。
* 更新 [区间运算符](../02_language_guide/02_Basic_Operators.md#range-operators) 章节,注意当半开区间运算符含有相同的起止索引时,其区间为空。
* 更新 [闭包引用类型](../02_language_guide/07_Closures.md#closures-are-reference-types) 章节,对于变量的捕获规则进行了阐明。
* 更新 [值溢出](../02_language_guide/27_Advanced_Operators.md#value-overflow) 章节,对有符号整数和无符号整数的溢出行为进行了阐明。
* 更新 [协议声明](../03_language_reference/06_Declarations.md#protocol-declaration) 章节,对协议声明时的作用域和成员等内容进行了阐明。
* 更新 [捕获列表](../02_language_guide/24_Automatic_Reference_Counting.md#defining-a-capture-list) 章节,对于闭包捕获列表中的弱引用和无主引用的使用语法进行了阐明。
* 更新 [运算符](../03_language_reference/02_Lexical_Structure.md#operator) 章节明确指明一些例子来说明自定义运算符所支持的特性如数学运算符各种符号Unicode 符号块等。
* 在函数作用域中的常量声明时可以不被初始化,它必须在第一次使用前被赋值。更多的内容,请看 [常量声明](../03_language_reference/06_Declarations.md#constant-declaration)。
* 在构造器中,常量属性有且仅能被赋值一次。更多内容,请看 [在构造过程中给常量属性赋值](../02_language_guide/14_Initialization.md#assigning-constant-properties-during-initialization)。
* 多个可选绑定现在可以在`if`语句后面以逗号分隔的赋值列表的方式出现,更多内容,请看 [可选绑定](../02_language_guide/01_The_Basics.md#optional-binding)。
* 一个 [可选链表达式](../03_language_reference/04_Expressions.md#optional-chaining-expression) 必须出现在后缀表达式中。
* 协议类型转换不再局限于 `@obj` 修饰的协议了。
* 在运行时可能会失败的类型转换可以使用 `as?``as!` 运算符,而确保不会失败的类型转换现在使用 `as` 运算符。更多内容,请看 [类型转换运算符](../03_language_reference/04_Expressions.md#type-casting-operator)。
### 2014-10-16
* 更新至 Swift 1.1。
* 新增 [失败构造器](../02_language_guide/14_Initialization.md#failable-initializers) 的完整指引。
* 在协议中新增了 [失败构造器要求](../02_language_guide/21_Protocols.md#failable-initializer-requirements) 的描述。
* 常量和变量的 `Any` 类型现可以包含函数实例。更新了有关 `Any` 相关的示例来展示如何在 `switch` 语句中如何检查并转换到一个函数类型。
* 带有原始值的枚举类型增加了一个 `rawValue` 属性替代 `toRaw()` 方法,同时使用了一个以 `rawValue` 为参数的失败构造器来替代 `fromRaw()` 方法。更多的内容,请看 [原始值](../02_language_guide/08_Enumerations.md#raw-values) 和 [带原始值的枚举类型](../03_language_reference/06_Declarations.md#enumerations-with-cases-of-a-raw-value-type)。
* 新增 [Failable Initializer](../03_language_reference/06_Declarations.md#failable-initializers) 的参考章节,它可以触发初始化失败。
* 自定义运算符现在可以包含 `?` 字符,更新了 [运算符](../03_language_reference/02_Lexical_Structure.md#operator) 涉及改进后的规则的部分,并且在 [自定义运算符](../02_language_guide/27-Advanced-Operators.md#custom-operators) 章节中删除了重复的运算符有效字符集合。
### 2014-08-18
* 描述 Swift 1.0 的新文档。Swift 是苹果公司发布的全新编程语言,用于 iOS 和 OS X 应用开发。
* 在协议中新增了 [对构造器的规定](../02_language_guide/21_Protocols.md#initializer-requirements) 章节。
* 新增 [类专属协议](../02_language_guide/21_Protocols.md#class-only-protocol) 章节。
* [断言](../02_language_guide/01_The_Basics.md#assertions-and-preconditions) 现在可以使用字符串内插语法,并删除了文档中有冲突的注释。
* 更新 [连接字符串和字符](../02_language_guide/03_Strings_and_Characters.md#concatenating-strings-and-characters) 章节来说明字符串和字符不能再用 `+` 号运算符或者复合加法运算符 `+=` 相互连接,这两种运算符现在只能用于字符串之间相连。请使用 `String` 类型的 `append` 方法在一个字符串的尾部增加单个字符。
* 在 [属性声明](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节增加了有关 `availability` 特性的一些内容。
* [可选类型](../02_language_guide/01_The_Basics.md#optionals) 若有值时,不再隐式的转换为 `true`,同样,若无值时,也不再隐式的转换为 `false`,这是为了避免在判别 optional `Bool` 的值时产生困惑。 替代的方案是,用`==``!=` 运算符显式地去判断 Optinal 是否是 `nil`,以确认其是否包含值。
* Swift 新增了一个 [Nil 合并运算符](../02_language_guide/02_Basic_Operators.md#nil-coalescing-operator) (`a ?? b`) , 该表达式中,如果 Optional `a` 的值存在,则取得它并返回,若 Optional `a``nil`,则返回默认值 `b`
* 更新和扩展 [字符串的比较](../02_language_guide/03_Strings_and_Characters.md#comparing-strings) ,用以反映和展示'字符串和字符的比较',以及'前缀prefix/后缀postfix比较'都开始基于扩展字符集extended grapheme clusters规范的等价比较。
* 现在,你可以通过下标赋值或者 [可选调用链](../02_language_guide/16_Optional_Chaining.md) 中的可变方法和操作符来给属性设值。相应地更新了有关 [通过可选链接访问属性](../02_language_guide/16_Optional_Chaining.md#accessing-properties-through-optional-chaining) 的内容,并扩展了 [通过可选链接调用方法](../02_language_guide/16_Optional_Chaining.md#calling-methods-through-optional-chaining) 时检查方法调用成功的示例,以显示如何检查属性设置是否成功。
* 在可选链中新增了 [访问可选类型的下标脚注](../02_language_guide/16_Optional_Chaining.md#accessing-subscripts-through-optional-chaining) 章节。
* 更新 [访问和修改数组](../02_language_guide/04_Collection_Types.md#accessing-and-modifying-a-dictionary) 章节以标示,从该版本起,不能再通过 `+=` 运算符给一个数组新增一个新的项。对应的替代方案是,使 `append` 方法,或者通过 `+=` 运算符来新增一个只有一个项的数组。
* 新增一处说明,在 [范围运算符](../02_language_guide/02_Basic_Operators.md#range-operators) 中,比如, `a..b``a..<b` ,起始值 `a` 不能大于结束值 `b`
* 重写 [继承](../02_language_guide/13_Inheritance.md) 篇章删除了本章中有关构造器重写的介绍性报道转而将更多的注意力放到新增的部分——子类的新功能以及如何通过重写overrides修改已有的功能。另外 [重写属性的 Getters 和 Setters](../02_language_guide/13_Inheritance.md#overriding-property-etters-and-setters) 中的例子已经被替换为展示如何重写一个 `description` 属性。 (而有关如何在子类的构造器中修改继承属性的默认值的例子,已经被移到 [构造过程](../02_language_guide/14_Initialization.md) 篇章。)
* 更新 [构造器的继承与重写](../02_language_guide/14_Initialization.md#initializer-inheritance-and-overriding) 章节以标示: 重写一个特定的构造器必须使用 `override` 修饰符。
* 更新 [Required 构造器](../02_language_guide/14_Initialization.md#required-initializers) 章节以标示:`required` 修饰符现在需要出现在所有子类的 required 构造器的声明中,而 required 构造器的实现,现在可以仅从父类自动继承。
* 中置Infix的 [运算符函数](../02_language_guide/27_Advanced_Operators.md#operator-functions) 不再需要 `@infix` 属性。
* [前置和后置运算符](../02_language_guide/27_Advanced_Operators.md#prefix-and-postfix-operators) 的 `@prefix``@postfix` 属性,已变更为 `prefix``postfix` 声明修饰符。
* 新增一处说明,在 Prefix 和 postfix 运算符被作用于同一个操作数时 [前置和后置运算符](../02_language_guide/27_Advanced_Operators.md#prefix-and-postfix-operators) 的执行顺序。
* [组合赋值运算符](../02_language_guide/27_Advanced_Operators.md#compound-assignment-operators) 的运算符函数不再使用 `@assignment` 属性来定义函数。
* 在定义 [自定义操作符](../02_language_guide/27_Advanced_Operators.md#custom-operators) 时,`修饰符Modifiers的出现顺序发生变化`。比如现在,你该编写 `prefix operator` 而不是 `operator prefix`
* 在 [声明修饰符](../03_language_reference/06_Declarations.md#declaration-modifiers) 章节新增了有关 `dynamic` 声明修饰符的内容。
* 新增有关 [字面量](../03_language_reference/02_Lexical_Structure.md#literal) 类型推导内容的内容。
* 新增更多有关柯里化函数的内容。
* 新增 [权限控制](../02_language_guide/26_Access_Control.md) 篇章。
* 更新 [字符串和字符](../02_language_guide/03_Strings_and_Characters.md) 章节,在 Swift 中现在 `Character` 类型代表的是扩展字符集extended grapheme cluster中的一个 Unicode为此新增了 [Extended Grapheme Clusters](../02_language_guide/03_Strings_and_Characters.md#extended-grapheme-clusters) 章节。同时,[Unicode 标量](../02_language_guide/03-Strings-And-Characters.md#unicode-scalars-representation) 和 [字符串比较](../02_language_guide/03-Strings-And-Characters.md#comparing-strings) 章节新增了更多内容。
* 更新 [字符串字面量](../02_language_guide/03_Strings_and_Characters.md#string-literals) 章节在一个字符串中Unicode 标量Unicode scalars`\u{n}`的形式来表示,`n` 是一个最大可以有8位的16进制数。
* `NSString` `length` 属性已被映射到 Swift 的内建 `String`类型。(注意,这两属性的类型是`utf16Count`,而非 `utf16count`)。
* Swift 的内建 `String` 类型不再拥有 `uppercaseString``lowercaseString` 属性。在 [字符串和字符](../02_language_guide/03_Strings_and_Characters.md) 章节中删除了对应部分,并更新了各种对应的代码用例。
* 新增 [没有外部名的构造器参数](../02_language_guide/14_Initialization.md#initializer-parameters-without-external-names) 章节。
* 新增 [Required 构造器](../02_language_guide/14_Initialization.md#required-initializers) 章节。
* 新增 [可选元组返回类型](../02_language_guide/06_Functions.md#optional-tuple-return-types) 章节。
* 更新 [类型注解](../02_language_guide/01_The_Basics.md#type-annotations) 章节,多个相关变量可以用"类型注解”在同一行中声明为同一类型。
* `@optional`, `@lazy`, `@final`, `@required` 等关键字被更新为 `optional`, `lazy`, `final`, `required` 参见 [声明修饰符](../03_language_reference/06_Declarations.md#declaration-modifiers)。
* 更新了整本书中有关 `..<` 的引用,从半闭区间改为了 [半开区间](../02_language_guide/02_Basic_Operators.md#half-open-range-operator)。
* 更新 [读取和修改字典](../02_language_guide/04_Collection_Types.md#accessing-and-modifying-a-dictionary) 章节, `Dictionary` 现在增加了一个 Boolean 型的属性:`isEmpty`
* 解释了哪些字符(集)可被用来定义 [自定义操作符](../02_language_guide/27_Advanced_Operators.md#custom-operators)。
* `nil` 和布尔运算中的 `true``false` 现在被定义为 [字面量](../03_language_reference/02_Lexical_Structure.md#literal)。
* Swift 中的数组 `Array` 类型从现在起具备了完整的值语义。具体内容被更新到 [集合的可变性](../02_language_guide/04_Collection_Types.md#mutability-of-collections) 和 [数组](../02_language_guide/04_Collection_Types.md#arrays) 两小节,以反映这个新的变化。 此外,还解释了如何给 Strings, Arrays 和 Dictionaries 进行赋值和拷贝。
* [数组类型速记语法](../02_language_guide/04_Collection_Types.md#array-type-shorthand-syntax) 从 `SomeType []` 更新为 ` [SomeType]`
* 新增 [字典类型的速记语法](../02_language_guide/04_Collection_Types.md#dictionary-type-shorthand-syntax) 章节,现在书写格式为: ` [KeyType: ValueType]`
* 新增 [字典键类型的哈希值](../02_language_guide/04_Collection_Types.md#hash-values-for-set-types) 章节。
* [闭包表达式](../02_language_guide/07_Closures.md#closure-expressions) 示例中使用新的全局函数 `sorted` 取代原先的全局函数 `sort` 去展示如何返回一个全新的数组。
* 更新 [结构体逐一成员构造器](../02_language_guide/14_Initialization.md#memberwise-initializers-for-structure-types) 章节,即使结构体的成员 `没有默认值`,逐一成员构造器也可以自动获得。
* [半开区间运算符](../02_language_guide/02_Basic_Operators.md#half-open-range-operator) 中`..` 更新为 `..<`
* 新增 [泛型拓展](../02_language_guide/22_Generics.md#extending-a-generic-type) 的示例。

View File

@ -0,0 +1,3 @@
# Swift 文档修订历史
本章描述了 Swift 文档修订历史。

View File

@ -1,22 +1,278 @@
> 2016.9.23: 已经更新到 Swift 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 译者记录
相关[issue](https://github.com/numbbbbb/the-swift-programming-language-in-chinese/issues/628)
- Functions: [crayygy](https://github.com/crayygy)
- Control Flow: [Realank](https://github.com/Realank)
- Closures: [LanfordCai](https://github.com/LanfordCai)
- Protocols: [chenmingbiao](https://github.com/chenmingbiao)
- The Basics:[chenmingbiao](https://github.com/chenmingbiao)
- Advanced Operators: [mmoaay](https://github.com/mmoaay)
### 2020-02-05
Language Reference:
- Attributes: [WhoJave](https://github.com/WhoJave)
- Statements: [chenmingjia](https://github.com/chenmingjia)
- Declarations: [chenmingjia](https://github.com/chenmingjia)
- Expressions: [chenmingjia](https://github.com/chenmingjia)
- Types: [lettleprince](https://github.com/lettleprince)
- Generic Parameters and Arguments: [chenmingjia](https://github.com/chenmingjia)
* 更新至 Swift 5.2。
* 在 [特殊名称方法](../03_language_reference/06_Declarations.md#methods-with-special-names) 章节中新增了有关让类、结构体和枚举的实例作为函数调用语法糖的内容。
* 更新 [下标选项](../02_language_guide/12_Subscripts.md#subscript-options) 章节,现在下标支持形参默认值。
* 更新 [自身类型](../03_language_reference/03_Types.md#self-type-h) 章节,现在 `Self` 可以在更多上下文中使用。
### 2019-09-10
* 更新至 Swift 5.1。
* 在 [不透明类型](../02_language_guide/23_Opaque_Types.md) 篇章中新增了有关函数返回值遵循指定协议,而不需要提供指定返回类型的内容。
* 在 [属性包装器](../02_language_guide/10_Properties.md#property-wrappers) 章节中新增了有关属性包装器的内容。
* 在 [冻结](../03_language_reference/07_Attributes.md#frozen) 章节中新增了有关因库演变而需要的枚举和结构体冻结。
* 新增 [隐式返回的函数](../02_language_guide/06_Functions.md#functions-with-an-implicit-return) 和 [简化 Getter 声明](../02_language_guide/10_Properties.md#shorthand-getter-declaration) 章节,其中包含函数省略 `return` 的内容。
* 在 [类型下标](../02_language_guide/12_Subscripts.md#type-subscripts) 章节中新增了有关在类型中使用下标的内容。
* 更新 [枚举 Case 模式匹配](../03_language_reference/08_Patterns.md#enumeration-case-pattern) 章节,现在枚举 case 模式匹配支持匹配可选值。
* 更新 [结构体的逐一成员构造器](../02_language_guide/14_Initialization.md#memberwise-initializers-for-structure-types) 章节,现在逐一成员构造器支持在属性有默认值时省略形参。
* 在 [动态查找成员](../03_language_reference/07_Attributes.md#dynamicmemberlookup) 章节中新增了有关在运行时用 key path 查找动态成员的内容。
* 在 [条件编译代码块](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 中的目标环境里添加了 `macCatalyst`
* 更新 [自身类型](../03_language_reference/03_Types.md#self-type-h) 章节,现在 `Self` 可以指向当前类,结构体或者枚举声明时的类型。
### 2019-03-25
* 更新至 Swift 5。
* 新增 [拓展字符串分隔符](../02_language_guide/03_Strings_and_Characters.md#extended-string-delimiters) 章节。更新 [字符串字面量](../03_language_reference/02_Lexical_Structure.md#string-literal) 章节,拓展有关字符串分隔符的内容。
* 新增 [动态调用](../03_language_reference/07_Attributes.md#dynamiccallable) 章节,其中包含使用 `dynamicCallable` 属性动态调用实例作为函数的内容。
* 新增 [unknown](../03_language_reference/07_Attributes.md#unknown) 和 [未来枚举匹配](../03_language_reference/05_Statements.md#future-case) 章节,其中包含了使用 `unknown` 来处理未来枚举可能发生改变的情形。
* 在 [Key-Path 表达式](../03_language_reference/04_Expressions.md#key-path-expression) 章节新增了有关标示 key path (\\.self) 的内容。
* 在 [可选编译块](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节新增了有关小于比较符 `<` 的内容。
### 2018-09-17
* 更新至 Swift 4.2。
* 在 [遍历枚举情形](../02_language_guide/08_Enumerations.md#iterating-over-enumeration-cases) 章节新增了有关访问所有枚举情形的内容。
* 在 [编译诊断](../03_language_reference/05_Statements.md#compile-time-diagnostic-statement) 章节新增了有关 `#error``#warning` 的内容。
* 在 [属性声明](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `inlinable``usableFromInline` 属性的内容。
* 在 [属性声明](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `requires-stored-property-inits``warn-unqualified-access` 属性的内容。
* 在 [可选编译块](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节新增了有关如何根据 Swift 编译器版本对代码进行对应编译处理的内容。
* 在 [字面量语法](../03_language_reference/04_Expressions.md#literal-expression) 章节新增了有关 `#dsohandle` 的内容。
### 2018-03-29
* 更新至 Swift 4.1。
* 在 [等价运算符](../02_language_guide/27_Advanced_Operators.md#equivalence-operators) 章节新增了有关等价运算符的合成实现的内容。
* 在 [声明](../03_language_reference/06_Declarations.md) 篇章中 [声明拓展](../03_language_reference/06_Declarations.md#extension-declaration) 章节和 [协议](../02_language_guide/21_Protocols.md) 篇章中 [有条件地遵循协议](../02_language_guide/21_Protocols.md#Conditionally-Conforming-to-a-Protocol) 章节新增了有关协议有条件遵循的内容。
* 在 [关联类型约束中使用协议](../02_language_guide/22_Generics.md#using-a-protocol-in-its-associated-types-constraints) 章节中新增了有关递归协议约束的内容。
* 在 [条件编译块](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节中新增了有关 `canImport()``targetEnvironment()` 平台条件的内容。
### 2017-12-04
* 更新至 Swift 4.0.3。
* 更新 [Key-Path 表达式](../03_language_reference/04_Expressions.md#key-path-expression) 章节,现在 key path 支持下标子路径。
### 2017-09-19
* 更新至 Swift 4.0。
* 在 [内存安全](../02_language_guide/25_Memory_Safety.md) 章节新增了有关内存互斥访问的内容。
* 新增 [带有泛型 Where 子句联类型](../02_language_guide/22_Generics.md#associated-types-with-a-generic-where-clause) 章节,现在可以使用泛型 `where` 子句约束关联类型。
* 在 [字符串和字符](../02_language_guide/03_Strings_and_Characters.md) 篇章中 [字面量](../02_language_guide/03_Strings_and_Characters.md#string-literals) 章节以及 [词法结构](../03_language_reference/02_Lexical_Structure.md) 篇章的 [字符串字面量](../03_language_reference/02_Lexical_Structure.md#string-literal) 章节中新增了有关多行字符串字面量的内容。
* 更新 [声明属性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 中 `objc` 属性的讨论,现在该属性会在更少的位置被推断出来。
* 新增 [范型下标](../02_language_guide/22_Generics.md#generic-subscripts) 章节,现在下标也支持范型特性了。
* 更新 [协议](../02_language_guide/21_Protocols.md) 篇章中 [协议组合](../02_language_guide/21_Protocols.md#protocol-composition) 章节和 [类型](../03_language_reference/03_Types.md) 篇章中 [协议组合类型](../03_language_reference/03_Types.md#protocol-composition-type-h) 章节的讨论,现在协议组合类型支持进行父类约束了。
* 更新 [拓展声明](../03_language_reference/06_Declarations.md#extension-declaration) 中有关协议扩展的讨论,现在它们不支持 `final` 特性了。
* 在 [断言和前置条件](../02_language_guide/01_The_Basics.md#assertions-and-preconditions) 章节中新增了部分前置条件和致命错误的内容。
### 2017-03-27
* 更新至 Swift 3.1。
* 新增 [范型 Where 子句扩展](../02_language_guide/22_Generics.md#extensions-with-a-generic-where-clause) 章节,包含需要的扩展内容。
* 在 [For-In 循环](../02_language_guide/05_Control_Flow.md#for-in-loops) 章节中新增了区间迭代的例子。
* 在 [可失败构造器](../02_language_guide/14_Initialization.md#failable-initializers) 章节中新增了可失败数值转换的例子。
* 在 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关使用 Swift 语言版本的 `available` 特性的内容 。
* 更新 [函数类型](../03_language_reference/03_Types.md#function-type-h) 章节中的讨论,注意在写函数类型时不允许使用参数标签。
* 更新 [条件编译块](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节中的 Swift 语言版本号的讨论,现在可以使用可选的补丁版本号。
* 更新 [函数类型](../03_language_reference/03_Types.md#function-type-h) 章节的讨论,现在 Swift 区分了采用多参数的函数和采用元组类型的单个参数的函数。
* 在 [表达式](../03_language_reference/04_Expressions.md) 篇章中删除了动态表达式的章节,现在 `type(of:)` 是 Swift 标准库函数。
### 2016-10-27
* 更新至 Swift 3.0.1。
* 更新 [自动引用计数](../02_language_guide/24_Automatic_Reference_Counting.md) 章节中有关 weak 和 unowned 引用的讨论。
* 在 [声明标识符](../03_language_reference/06_Declarations.md#declaration-modifiers) 章节中新增了有关新的标识符 `unowned``unowend(safe)``unowned(unsafe)` 的内容。
* 在 [Any 和 AnyObject 的类型转换](../02_language_guide/18_Type_Casting.md#type-casting-for-any-and-anyobject) 章节中新增了一处说明,有关使用类型 `Any` 作为可选值。
* 更新 [表达式](../03_language_reference/04_Expressions.md) 章节,把括号表达式和元组表达式的描述分开。
### 2016-09-13
* 更新至 Swift 3.0。
* 更新 [函数](../02_language_guide/06_Functions.md) 篇章和 [函数声明](../03_language_reference/06_Declarations.md#function-declaration) 章节中有关函数的讨论,所有函数参数默认都有函数标签。
* 更新 [高级操作符](../02_language_guide/27_Advanced_Operators.md) 篇章中有关操作符的讨论,现在你可以作为类型函数来实现,替代之前的全局函数实现方式。
* 在 [访问控制](../02_language_guide/26_Access_Control.md) 章节中新增有关对新的访问级别描述符 `open``fileprivate` 的内容。
* 更新 [函数声明](../03_language_reference/06_Declarations.md#function-declaration) 章节中有关 `inout` 的讨论,注意它现在出现在参数类型的前面,而不是在参数名称的前面。
* 更新 [逃逸闭包](../02_language_guide/07_Closures.md#escaping-closures) 和 [自动闭包](../02_language_guide/07_Closures.md#autoclosures) 章节还有 [属性](../03_language_reference/07_Attributes.md) 篇章中有关 `@noescape``@autoclosure` 的讨论,现在他们是类型属性,而不是定义属性。
* 在 [高级操作符](../02_language_guide/27_Advanced_Operators.md) 篇章中 [自定义中缀操作符的优先级](./02_language_guide/27_Advanced_Operators.md#precedence-and-associativity-for-custom-infix-operators) 章节和 [定义](../03_language_reference/06_Declarations.md) 篇章中 [优先级组声明](../03_language_reference/06_Declarations.md#precedence-group-declaration-modifiers) 章节中新增了有关操作符优先级组的内容。
* 更新一些讨论,使用 macOS 替换掉 OS X Error 替换掉 ErrorProtocol。更新一些协议名称比如使用 ExpressibleByStringLiteral 替换掉 StringLiteralConvertible。
* 更新 [泛型](../02_language_guide/22_Generics.md) 篇章中 [泛型 Where 语句](../02_language_guide/22_Generics.md#extensions-with-a-generic-where-clause) 章节和 [泛型形参和实参](../03_language_reference/09_Generic_Parameters_and_Arguments.md) 篇章的讨论,现在泛型的 where 语句写在一个声明的最后。
* 更新 [逃逸闭包](../02_language_guide/07_Closures.md#escaping-closures) 章节中的讨论,现在闭包默认为非逃逸的。
* 更新 [基础部分](../02_language_guide/01_The_Basics.md) 篇章中 [可选绑定](../02_language_guide/01_The_Basics.md#optional-binding) 章节和 [语句](../03_language_reference/05_Statements.md) 篇章中 [While 语句](../03_language_reference/05_Statements.md#while-statement) 章节中的讨论,现在 if`while``guard` 语句使用逗号分隔条件列表,不需要使用 `where` 语句。
* 在 [控制流](../02_language_guide/05_Control_Flow.md) 篇章中 [Switch](../02_language_guide/05_Control_Flow.md#switch) 章节和 [语句](../03_language_reference/05_Statements.md) 篇章中 [Switch 语句](../03_language_reference/05_Statements.md#switch-statement) 章节中新增了 switch cases 可以使用多模式的内容。
* 更新 [函数类型](../03_language_reference/03_Types.md#function-type-h) 章节有关现在函数参数标签不包含在函数类型中的讨论。
* 更新 [协议](../02_language_guide/21_Protocols.md) 篇章中 [协议组合](../02_language_guide/21_Protocols.md#protocol-composition) 章节和 [类型](../03_language_reference/03_Types.md) 篇章中 [协议组合类型](../03_language_reference/03_Types.md#protocol-composition-type-h) 章节中有关使用新的 Protocol1 & Protocol2 语法的内容。
* 更新动态类型表达式章节中使用新的 `type(of:)` 表达式的讨论。
* 更新 [行控制表达式](../03_language_reference/05_Statements.md#line-control-statement) 章节中使用 `#sourceLocation(file:line:)` 表达式的讨论。
* 更新 [永不返回函数](../03_language_reference/06_Declarations.md#functions-that-never-return) 章节中使用 新的 `Never` 类型的讨论。
* 在 [字面量表达式](../03_language_reference/04_Expressions.md#literal-expression) 章节中新增了有关 `playground` 字面量的内容。
* 更新 [In-Out 参数](../03_language_reference/06_Declarations.md#in-out-parameters) 章节,标明只有非逃逸闭包能捕获 `in-out` 参数。
* 更新 [默认参数值](../02_language_guide/06_Functions.md#default-parameter-values) 章节,现在默认参数不能在调用时候重新排序。
* 更新 [属性](../03_language_reference/07_Attributes.md) 篇章中有关属性参数使用分号的说明。
* 在 [重新抛出函数和方法](../03_language_reference/06_Declarations.md#rethrowing-functions-and-methods) 章节中新增了有关在 catch 代码块中抛出错误的重新抛出函数的内容。
* 在 [Selector 表达式](../03_language_reference/04_Expressions.md#selector-expression7) 章节中新增了中有关访问 Objective-C 中 Selector 的 getter 和 setter 的内容。
* 在 [类型别名声明](../03_language_reference/06_Declarations.md#type-alias-declaration) 章节中中新增了有关泛型类型别名和在协议内使用类型别名的内容。
* 更新 [函数类型](../03_language_reference/03_Types.md#function-type-h) 章节中有关函数类型的讨论,标明函数类型作为参数类型必须使用括号包裹。
* 更新 [属性](../03_language_reference/07_Attributes.md) 篇章,标明 `@IBAction``@IBOutlet``@NSManaged` 隐式含有 `@objc` 属性。
* 在 [声明属性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `@GKInspectable` 的内容。
* 更新 [可选协议要求](../02_language_guide/21_Protocols.md#optional-protocol-requirements) 章节中有关只能在与 `Objective-C` 交互的代码中才能使用可选协议要求的内容。
* 删除 [函数声明](../03_language_reference/06_Declarations.md#function-declaration) 章节中有关显式使用 `let` 关键字作为函数参数的内容。
* 删除 [语句](../03_language_reference/05_Statements.md) 章节中有关 `Boolean` 协议的内容, 现在这个协议已经被 Swift 标准库删除。
* 更正 [声明属性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@NSApplicationMain` 协议的内容。
### 2016-03-21
* 更新至 Swift 2.2。
* 在 [编译配置语句](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节新增了中有关如何根据 Swift 版本进行条件编译。
* 在 [显示成员表达式](../03_language_reference/04_Expressions.md#explicit-member-expression) 章节中新增了有关如何区分只有参数名不同的方法和构造器的内容。
* 在 [选择器表达式](../03_language_reference/04_Expressions.md#selector-expression7) 章节中新增了了针对 Objective-C 选择器的 `#selector` 语法。
* 更新 [关联类型](../02_language_guide/22_Generics.md#associated-types) 和 [协议关联类型声明](../03_language_reference/06_Declarations.md#protocol-associated-type-declaration) 章节中有关使用 `associatedtype` 关键词修饰关联类型的讨论。
* 更新 [可失败构造器](../02_language_guide/14_Initialization.md#failable-initializers) 章节中有关当构造器在实例完全初始化之前返回 `nil` 的相关内容。
* 在 [比较运算符](../02_language_guide/02_Basic_Operators.md#comparison-operators) 章节中新增了比较元组的内容。
* 在 [关键字和标点符号](../03_language_reference/02_Lexical_Structure.md#keywords-and-punctuation) 章节中新增了使用关键字作为外部参数名的内容。
* 更新 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@objc` 特性的讨论,并指出枚举和枚举用例。
* 更新 [操作符](../03_language_reference/02_Lexical_Structure.md#operator) 章节中对于自定义运算符的包含了 `.` 的讨论。
* 在 [重新抛出错误的函数和方法](../03_language_reference/06_Declarations.md#rethrowing-functions-and-methods) 章节中新增了一处说明,重新抛出错误函数不能直接抛出错误。
* 在 [属性观察器](../02_language_guide/10_Properties.md#property-observers) 章节中新增了一处说明,当作为 in-out 参数传递属性时,属性观察器的调用行为。
* 在 [Swift 初见](../01_welcome_to_swift/03_a_swift_tour.md) 篇章中新增了错误处理的章节。
* 更新 [弱引用](../02_language_guide/24_Automatic_Reference_Counting.md#weak-references) 章节中的图片用以更清楚的展示重新分配过程。
* 删除 C 语言风格的 `for` 循环,`++` 前缀和后缀运算符,以及 `--` 前缀和后缀运算符。
* 删除对变量函数参数和柯里化函数的特殊语法的讨论。
### 2015-10-20
* 更新至 Swift 2.1。
* 更新 [字符串插值](../02_language_guide/03_Strings_and_Characters.md#string-interpolation) 和 [字符串字面量](../03_language_reference/02_Lexical_Structure.md#string-literal) 章节,现在字符串插值可包含字符串字面量。
* 在 [逃逸闭包](../02_language_guide/07_Closures.md#escaping-closures) 章节中新增了有关 `@noescape` 属性的相关内容。
* 更新 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 和 [编译配置语句](../03_language_reference/05_Statements.md#Conditional-Compilation-Block) 章节中与 tvOS 相关的内容。
* 在 [In-Out 参数](../03_language_reference/06_Declarations.md#in-out-parameters) 章节中新增了与 in-out 参数行为相关的内容。
* 在 [捕获列表](../03_language_reference/04_Expressions.md#capture-lists) 章节新增了有关指定闭包捕获列表被捕获时捕获值的相关内容。
* 更新 [可选链式调用访问属性](../02_language_guide/16_Optional_Chaining.md#accessing-properties-through-optional-chaining) 章节,阐明了如何通过可选链式调用进行赋值。
* 改进 [自动闭包](../02_language_guide/07_Closures.md#autoclosures) 章节中对自闭包的讨论。
* 在 [Swift 初见](../01_welcome_to_swift/03_a_swift_tour.md) 篇章中新增了一个使用 `??` 操作符的例子。
### 2015-09-16
* 更新至 Swift 2.0。
* 在 [错误处理](../02_language_guide/17_Error_Handling.md) 篇章中新增了有关错误处理的相关内容,包括 [Do 语句](../03_language_reference/05_Statements.md#do-statement)、 [Throw 语句](../03_language_reference/05_Statements.md#throw-statement)、 [Defer 语句](../03_language_reference/05_Statements.md##defer-statements) 以及 [try 运算符](../03_language_reference/04_Expressions.md#try-operator)。
* 更新 [错误表示和抛出](../02_language_guide/17_Error_Handling.md#representing-and-throwing-errors) 章节,现在所有类型都可以遵循 `ErrorType` 协议了。
* 在 [将错误装换成可选值](../02_language_guide/17_Error_Handling.md#converting-errors-to-optional-values) 篇章增加了 `try?` 关键字相关内容。
* 在 [枚举](../02_language_guide/08_Enumerations.md) 篇章的 [递归枚举](../02_language_guide/08_Enumerations.md#recursive-enumerations) 章节以及以及 [声明](../03_language_reference/06_Declarations.md) 篇章的 [任意类型用例的枚举](../03_language_reference/06_Declarations.md#enumerations-with-cases-of-any-type) 章节中新增了递归枚举相关内容。
* 在 [控制流](../02_language_guide/05_Control_Flow.md) 篇章的 [API 可用性检查](../02_language_guide/05_Control_Flow.md#checking-api-availability) 章节和 [语句](../03_language_reference/05_Statements.md) 篇章的 [可用性条件](../03_language_reference/05_Statements.md#availability-condition) 章节中新增了有关 API 可用性检查相关的内容。
* 在 [控制流](../02_language_guide/05_Control_Flow.md) 篇章的 [尽早退出](../02_language_guide/05_Control_Flow.md#early-exit) 章节和 [语句](../03_language_reference/05_Statements.md) 篇章的 [Guard 语句](../03_language_reference/05_Statements.md#guard-statement) 章节新增了与 `guard` 语句相关的内容。
* 在 [协议](../02_language_guide/21_Protocols.md) 篇章中 [协议扩展](../02_language_guide/21_Protocols.md#protocol-extensions) 章节中新增了有关协议扩展的内容。
* 在 [访问控制](../02_language_guide/26_Access_Control.md) 篇章的 [单元测试 target 的访问级别](../02_language_guide/26_Access_Control.md#access-levels-for-unit-test-targets) 章节中新增了有关单元测试访问控制相关的内容。
* 在 [模式](../03_language_reference/08_Patterns.md) 篇章的 [可选模式](../03_language_reference/08_Patterns.md#optional-pattern) 章节中新增了可选模式相关内容。
* 更新 [Repeat-While](../02_language_guide/05_Control_Flow.md#repeat-while) 章节中有关 `repeat-while` 循环相关的内容。
* 更新 [字符串和字符](../02_language_guide/03_Strings_and_Characters.md) 章节,现在 `String` 类型在 Swift 标准库中不再遵循 `CollectionType` 协议。
* 在 [常量与变量打印](../02_language_guide/01_The_Basics.md#printing) 章节中新增了新 Swift 标准库中有关 `print(-:separator:terminator) ` 相关内容。
* 在 [枚举](../02_language_guide/08_Enumerations.md) 篇章的 [原始值的隐式赋值](../02_language_guide/08_Enumerations.md#implicitly-assigned-raw-values) 章节和 [声明](../03_language_reference/06_Declarations.md) 篇章的 [包含原始值类型的枚举](../03_language_reference/06_Declarations.md#enumerations-with-cases-of-a-raw-value-type) 章节中新增了有关包含 `String` 原始值的枚举用例的行为相关内容。
* 在 [自动闭包](../02_language_guide/07_Closures.md#autoclosures) 章节中新增了有关 `@autoclosure` 特性的相关内容,包括它的 `@autoclosure(escaping)` 形式。
* 更新 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@avaliable``warn-unused-result` 特性的相关内容。
* 更新 [类型特性](../03_language_reference/07_Attributes.md#type-attributes) 章节中有关 `@convention` 特性的相关内容。
* 在 [可选绑定](../02_language_guide/01_The_Basics.md#optional-binding) 章节中新增了有关使用 `where` 子句进行多可选绑定的相关内容。
* 在 [字符串字面量](../03_language_reference/02_Lexical_Structure.md#string-literal) 章节中新增了有关在编译时使用 `+` 运算符拼接字符串字面量的相关内容。
* 在 [元类型](../03_language_reference/03_Types.md#metatype-type-h) 章节中新增了有关元类型值的比较和使用它们通过构造器表达式构造实例相关内容。
* 在 [断言调试](../02_language_guide/01_The_Basics.md#debugging-with-assertions) 章节中新增了一处说明,有关用户定义断言何时会失效。
* 更新 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节中对 `@NSManaged` 特性的讨论,现在这个特性可以被应用到一个确定实例方法。
* 更新 [可变参数](../02_language_guide/06_Functions.md#variadic-parameters) 章节,现在可变参数可以声明在函数参数列表的任意位置中。
* 在 [重写可失败构造器](../02_language_guide/14_Initialization.md#overriding-a-failable-initializer) 章节中新增了有关非可失败构造器相当于一个可失败构造器通过父类构造器的结果进行强制拆包的相关内容。
* 在 [任意类型用例的枚举](../03_language_reference/06_Declarations.md#enumerations-with-cases-of-any-type) 章节中新增了有关枚举用例作为函数的内容。
* 在 [构造器表达式](../03_language_reference/04_Expressions.md#initializer-expression) 章节中新增了有关显式引用一个构造器相关内容。
* 在 [编译控制语句](../03_language_reference/05_Statements.md#compiler-control-statements) 章节中新增了有关编译内容以及行控制语句相关内容。
* 在 [元类型](../03_language_reference/03_Types.md#metatype-type-h) 章节新增了一处说明,有关如何从元类型值中构造类实例相关内容。
* 在 [弱引用](../02_language_guide/24_Automatic_Reference_Counting.md#weak-references) 章节新增了一处说明,有关弱引用作为缓存所存在的不足。
* 更新 [类型特性](../02_language_guide/10_Properties.md#type-properties) 章节,提到了存储型特性其实是懒加载。
* 更新 [捕获类型](../02_language_guide/07_Closures.md#capturing-values) 章节,阐明了变量和常量在闭包中如何被捕获。
* 更新 [声明特性](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节,用以描述何时在类中使用 `@objc` 关键字。
* 在 [错误处理](../02_language_guide/17_Error_Handling.md#handling-errors) 章节中新增了一处说明,有关执行 `throw` 语句的性能。在 [Do 语句](../03_language_reference/05_Statements.md#do-statement) 章节的 do 语句部分也新增了类似内容。
* 更新 [类型特性](../02_language_guide/10_Properties.md#type-properties) 章节中有关类、结构体和枚举的存储型和计算型特性相关的内容。
* 更新 [Break 语句](../03_language_reference/05_Statements.md#break-statement) 章节中有关带标签的 break 语句相关内容。
* 在 [属性观察器](../02_language_guide/10_Properties.md#property-observers) 章节更新了一处说明,用来明确 `willSet``didSet` 观察器的行为。
* 在 [访问级别](../02_language_guide/26_Access_Control.md#access-levels) 章节新增了有关 `private` 作用域的相关内容说明。
* 在 [弱引用](../02_language_guide/24_Automatic_Reference_Counting.md#weak-references) 章节新增了有关弱应用在垃圾回收系统和 ARC 之间的区别的说明。
* 更新 [字符串字面量中特殊字符](../02_language_guide/03_Strings_and_Characters.md#special-characters-in-string-literals) 章节,对 Unicode 标量更精确定义。
### 2015-04-08
* 更新至 Swift 1.2。
* Swift 现在自身提供了一个 `Set` 集合类型,更多内容,请看 [Sets](../02_language_guide/04_Collection_Types.md#sets) 。
* `@autoclosure` 现在是一个参数声明的属性,而不是参数类型的属性。这里还有一个新的参数声明属性 `@noescape`。更多内容,请看 [属性声明](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 。
* 对于类型属性和方法现在可以使用 `static` 关键字作为声明描述符,更多内容,请看 [类型变量属性](../03_language_reference/06_Declarations.md#type-variable-properties)。
* Swift 现在包含一个 `as?``as!` 的向下可失败类型转换运算符。更多内容,请看 [协议遵循性检查](../02_language_guide/21_Protocols.md#checking-for-protocol-conformance)。
* 新增 [字符串索引](../02_language_guide/03_Strings_and_Characters.md#string-indices) 的新指导章节。
* 在 [溢出运算符](../02_language_guide/27_Advanced_Operators.md#overflow-operators) 一节中删除了溢出除运算符(`&/`)和求余溢出运算符(`&%`)。
* 更新常量和常量属性在声明和构造时的规则,更多内容,请看 [常量声明](../03_language_reference/06_Declarations.md#constant-declaration) 。
* 更新字符串字面量中 Unicode 标量集的定义,请看 [字符串字面量中的特殊字符](../02_language_guide/03_Strings_and_Characters.md#special-characters-in-string-literals) 。
* 更新 [区间运算符](../02_language_guide/02_Basic_Operators.md#range-operators) 章节,注意当半开区间运算符含有相同的起止索引时,其区间为空。
* 更新 [闭包引用类型](../02_language_guide/07_Closures.md#closures-are-reference-types) 章节,对于变量的捕获规则进行了阐明。
* 更新 [值溢出](../02_language_guide/27_Advanced_Operators.md#value-overflow) 章节,对有符号整数和无符号整数的溢出行为进行了阐明。
* 更新 [协议声明](../03_language_reference/06_Declarations.md#protocol-declaration) 章节,对协议声明时的作用域和成员等内容进行了阐明。
* 更新 [捕获列表](../02_language_guide/24_Automatic_Reference_Counting.md#defining-a-capture-list) 章节,对于闭包捕获列表中的弱引用和无主引用的使用语法进行了阐明。
* 更新 [运算符](../03_language_reference/02_Lexical_Structure.md#operator) 章节明确指明一些例子来说明自定义运算符所支持的特性如数学运算符各种符号Unicode 符号块等。
* 在函数作用域中的常量声明时可以不被初始化,它必须在第一次使用前被赋值。更多的内容,请看 [常量声明](../03_language_reference/06_Declarations.md#constant-declaration)。
* 在构造器中,常量属性有且仅能被赋值一次。更多内容,请看 [在构造过程中给常量属性赋值](../02_language_guide/14_Initialization.md#assigning-constant-properties-during-initialization)。
* 多个可选绑定现在可以在`if`语句后面以逗号分隔的赋值列表的方式出现,更多内容,请看 [可选绑定](../02_language_guide/01_The_Basics.md#optional-binding)。
* 一个 [可选链表达式](../03_language_reference/04_Expressions.md#optional-chaining-expression) 必须出现在后缀表达式中。
* 协议类型转换不再局限于 `@obj` 修饰的协议了。
* 在运行时可能会失败的类型转换可以使用 `as?``as!` 运算符,而确保不会失败的类型转换现在使用 `as` 运算符。更多内容,请看 [类型转换运算符](../03_language_reference/04_Expressions.md#type-casting-operator)。
### 2014-10-16
* 更新至 Swift 1.1。
* 新增 [失败构造器](../02_language_guide/14_Initialization.md#failable-initializers) 的完整指引。
* 在协议中新增了 [失败构造器要求](../02_language_guide/21_Protocols.md#failable-initializer-requirements) 的描述。
* 常量和变量的 `Any` 类型现可以包含函数实例。更新了有关 `Any` 相关的示例来展示如何在 `switch` 语句中如何检查并转换到一个函数类型。
* 带有原始值的枚举类型增加了一个 `rawValue` 属性替代 `toRaw()` 方法,同时使用了一个以 `rawValue` 为参数的失败构造器来替代 `fromRaw()` 方法。更多的内容,请看 [原始值](../02_language_guide/08_Enumerations.md#raw-values) 和 [带原始值的枚举类型](../03_language_reference/06_Declarations.md#enumerations-with-cases-of-a-raw-value-type)。
* 新增 [Failable Initializer](../03_language_reference/06_Declarations.md#failable-initializers) 的参考章节,它可以触发初始化失败。
* 自定义运算符现在可以包含 `?` 字符,更新了 [运算符](../03_language_reference/02_Lexical_Structure.md#operator) 涉及改进后的规则的部分,并且在 [自定义运算符](../02_language_guide/27-Advanced-Operators.md#custom-operators) 章节中删除了重复的运算符有效字符集合。
### 2014-08-18
* 描述 Swift 1.0 的新文档。Swift 是苹果公司发布的全新编程语言,用于 iOS 和 OS X 应用开发。
* 在协议中新增了 [对构造器的规定](../02_language_guide/21_Protocols.md#initializer-requirements) 章节。
* 新增 [类专属协议](../02_language_guide/21_Protocols.md#class-only-protocol) 章节。
* [断言](../02_language_guide/01_The_Basics.md#assertions-and-preconditions) 现在可以使用字符串内插语法,并删除了文档中有冲突的注释。
* 更新 [连接字符串和字符](../02_language_guide/03_Strings_and_Characters.md#concatenating-strings-and-characters) 章节来说明字符串和字符不能再用 `+` 号运算符或者复合加法运算符 `+=` 相互连接,这两种运算符现在只能用于字符串之间相连。请使用 `String` 类型的 `append` 方法在一个字符串的尾部增加单个字符。
* 在 [属性声明](../03_language_reference/07_Attributes.md#Ideclaration-attributes) 章节增加了有关 `availability` 特性的一些内容。
* [可选类型](../02_language_guide/01_The_Basics.md#optionals) 若有值时,不再隐式的转换为 `true`,同样,若无值时,也不再隐式的转换为 `false`,这是为了避免在判别 optional `Bool` 的值时产生困惑。 替代的方案是,用`==``!=` 运算符显式地去判断 Optinal 是否是 `nil`,以确认其是否包含值。
* Swift 新增了一个 [Nil 合并运算符](../02_language_guide/02_Basic_Operators.md#nil-coalescing-operator) (`a ?? b`) , 该表达式中,如果 Optional `a` 的值存在,则取得它并返回,若 Optional `a``nil`,则返回默认值 `b`
* 更新和扩展 [字符串的比较](../02_language_guide/03_Strings_and_Characters.md#comparing-strings) ,用以反映和展示'字符串和字符的比较',以及'前缀prefix/后缀postfix比较'都开始基于扩展字符集extended grapheme clusters规范的等价比较。
* 现在,你可以通过下标赋值或者 [可选调用链](../02_language_guide/16_Optional_Chaining.md) 中的可变方法和操作符来给属性设值。相应地更新了有关 [通过可选链接访问属性](../02_language_guide/16_Optional_Chaining.md#accessing-properties-through-optional-chaining) 的内容,并扩展了 [通过可选链接调用方法](../02_language_guide/16_Optional_Chaining.md#calling-methods-through-optional-chaining) 时检查方法调用成功的示例,以显示如何检查属性设置是否成功。
* 在可选链中新增了 [访问可选类型的下标脚注](../02_language_guide/16_Optional_Chaining.md#accessing-subscripts-through-optional-chaining) 章节。
* 更新 [访问和修改数组](../02_language_guide/04_Collection_Types.md#accessing-and-modifying-a-dictionary) 章节以标示,从该版本起,不能再通过 `+=` 运算符给一个数组新增一个新的项。对应的替代方案是,使 `append` 方法,或者通过 `+=` 运算符来新增一个只有一个项的数组。
* 新增一处说明,在 [范围运算符](../02_language_guide/02_Basic_Operators.md#range-operators) 中,比如, `a..b``a..<b` ,起始值 `a` 不能大于结束值 `b`
* 重写 [继承](../02_language_guide/13_Inheritance.md) 篇章删除了本章中有关构造器重写的介绍性报道转而将更多的注意力放到新增的部分——子类的新功能以及如何通过重写overrides修改已有的功能。另外 [重写属性的 Getters 和 Setters](../02_language_guide/13_Inheritance.md#overriding-property-etters-and-setters) 中的例子已经被替换为展示如何重写一个 `description` 属性。 (而有关如何在子类的构造器中修改继承属性的默认值的例子,已经被移到 [构造过程](../02_language_guide/14_Initialization.md) 篇章。)
* 更新 [构造器的继承与重写](../02_language_guide/14_Initialization.md#initializer-inheritance-and-overriding) 章节以标示: 重写一个特定的构造器必须使用 `override` 修饰符。
* 更新 [Required 构造器](../02_language_guide/14_Initialization.md#required-initializers) 章节以标示:`required` 修饰符现在需要出现在所有子类的 required 构造器的声明中,而 required 构造器的实现,现在可以仅从父类自动继承。
* 中置Infix的 [运算符函数](../02_language_guide/27_Advanced_Operators.md#operator-functions) 不再需要 `@infix` 属性。
* [前置和后置运算符](../02_language_guide/27_Advanced_Operators.md#prefix-and-postfix-operators) 的 `@prefix``@postfix` 属性,已变更为 `prefix``postfix` 声明修饰符。
* 新增一处说明,在 Prefix 和 postfix 运算符被作用于同一个操作数时 [前置和后置运算符](../02_language_guide/27_Advanced_Operators.md#prefix-and-postfix-operators) 的执行顺序。
* [组合赋值运算符](../02_language_guide/27_Advanced_Operators.md#compound-assignment-operators) 的运算符函数不再使用 `@assignment` 属性来定义函数。
* 在定义 [自定义操作符](../02_language_guide/27_Advanced_Operators.md#custom-operators) 时,`修饰符Modifiers的出现顺序发生变化`。比如现在,你该编写 `prefix operator` 而不是 `operator prefix`
* 在 [声明修饰符](../03_language_reference/06_Declarations.md#declaration-modifiers) 章节新增了有关 `dynamic` 声明修饰符的内容。
* 新增有关 [字面量](../03_language_reference/02_Lexical_Structure.md#literal) 类型推导内容的内容。
* 新增更多有关柯里化函数的内容。
* 新增 [权限控制](../02_language_guide/26_Access_Control.md) 篇章。
* 更新 [字符串和字符](../02_language_guide/03_Strings_and_Characters.md) 章节,在 Swift 中现在 `Character` 类型代表的是扩展字符集extended grapheme cluster中的一个 Unicode为此新增了 [Extended Grapheme Clusters](../02_language_guide/03_Strings_and_Characters.md#extended-grapheme-clusters) 章节。同时,[Unicode 标量](../02_language_guide/03-Strings-And-Characters.md#unicode-scalars-representation) 和 [字符串比较](../02_language_guide/03-Strings-And-Characters.md#comparing-strings) 章节新增了更多内容。
* 更新 [字符串字面量](../02_language_guide/03_Strings_and_Characters.md#string-literals) 章节在一个字符串中Unicode 标量Unicode scalars`\u{n}`的形式来表示,`n` 是一个最大可以有8位的16进制数。
* `NSString` `length` 属性已被映射到 Swift 的内建 `String`类型。(注意,这两属性的类型是`utf16Count`,而非 `utf16count`)。
* Swift 的内建 `String` 类型不再拥有 `uppercaseString``lowercaseString` 属性。在 [字符串和字符](../02_language_guide/03_Strings_and_Characters.md) 章节中删除了对应部分,并更新了各种对应的代码用例。
* 新增 [没有外部名的构造器参数](../02_language_guide/14_Initialization.md#initializer-parameters-without-external-names) 章节。
* 新增 [Required 构造器](../02_language_guide/14_Initialization.md#required-initializers) 章节。
* 新增 [可选元组返回类型](../02_language_guide/06_Functions.md#optional-tuple-return-types) 章节。
* 更新 [类型注解](../02_language_guide/01_The_Basics.md#type-annotations) 章节,多个相关变量可以用"类型注解”在同一行中声明为同一类型。
* `@optional`, `@lazy`, `@final`, `@required` 等关键字被更新为 `optional`, `lazy`, `final`, `required` 参见 [声明修饰符](../03_language_reference/06_Declarations.md#declaration-modifiers)。
* 更新了整本书中有关 `..<` 的引用,从半闭区间改为了 [半开区间](../02_language_guide/02_Basic_Operators.md#half-open-range-operator)。
* 更新 [读取和修改字典](../02_language_guide/04_Collection_Types.md#accessing-and-modifying-a-dictionary) 章节, `Dictionary` 现在增加了一个 Boolean 型的属性:`isEmpty`
* 解释了哪些字符(集)可被用来定义 [自定义操作符](../02_language_guide/27_Advanced_Operators.md#custom-operators)。
* `nil` 和布尔运算中的 `true``false` 现在被定义为 [字面量](../03_language_reference/02_Lexical_Structure.md#literal)。
* Swift 中的数组 `Array` 类型从现在起具备了完整的值语义。具体内容被更新到 [集合的可变性](../02_language_guide/04_Collection_Types.md#mutability-of-collections) 和 [数组](../02_language_guide/04_Collection_Types.md#arrays) 两小节,以反映这个新的变化。 此外,还解释了如何给 Strings, Arrays 和 Dictionaries 进行赋值和拷贝。
* [数组类型速记语法](../02_language_guide/04_Collection_Types.md#array-type-shorthand-syntax) 从 `SomeType []` 更新为 ` [SomeType]`
* 新增 [字典类型的速记语法](../02_language_guide/04_Collection_Types.md#dictionary-type-shorthand-syntax) 章节,现在书写格式为: ` [KeyType: ValueType]`
* 新增 [字典键类型的哈希值](../02_language_guide/04_Collection_Types.md#hash-values-for-set-types) 章节。
* [闭包表达式](../02_language_guide/07_Closures.md#closure-expressions) 示例中使用新的全局函数 `sorted` 取代原先的全局函数 `sort` 去展示如何返回一个全新的数组。
* 更新 [结构体逐一成员构造器](../02_language_guide/14_Initialization.md#memberwise-initializers-for-structure-types) 章节,即使结构体的成员 `没有默认值`,逐一成员构造器也可以自动获得。
* [半开区间运算符](../02_language_guide/02_Basic_Operators.md#half-open-range-operator) 中`..` 更新为 `..<`
* 新增 [泛型拓展](../02_language_guide/22_Generics.md#extending-a-generic-type) 的示例。
感谢阅读!

View File

@ -1,48 +1,48 @@
# Summary
* 欢迎使用 Swift
* [关于 Swift](chapter1/01_about_swift.md)
* [版本兼容性](chapter1/02_version_compatibility.md)
* [Swift 初见](chapter1/03_a_swift_tour.md)
* [Swift 版本历史记录](chapter1/04_revision_history.md)
* [关于 Swift](01_welcome_to_swift/01_about_swift.md)
* [版本兼容性](01_welcome_to_swift/02_version_compatibility.md)
* [Swift 初见](01_welcome_to_swift/03_a_swift_tour.md)
* [Swift 版本历史记录](04_revision_history/04_revision_history.md)
* Swift 教程
* [基础部分](chapter2/01_The_Basics.md)
* [基本运算符](chapter2/02_Basic_Operators.md)
* [字符串和字符](chapter2/03_Strings_and_Characters.md)
* [集合类型](chapter2/04_Collection_Types.md)
* [控制流](chapter2/05_Control_Flow.md)
* [函数](chapter2/06_Functions.md)
* [闭包](chapter2/07_Closures.md)
* [枚举](chapter2/08_Enumerations.md)
* [类和结构体](chapter2/09_Structures_And_Classes.md)
* [属性](chapter2/10_Properties.md)
* [方法](chapter2/11_Methods.md)
* [下标](chapter2/12_Subscripts.md)
* [继承](chapter2/13_Inheritance.md)
* [构造过程](chapter2/14_Initialization.md)
* [析构过程](chapter2/15_Deinitialization.md)
* [可选链](chapter2/16_Optional_Chaining.md)
* [错误处理](chapter2/17_Error_Handling.md)
* [类型转换](chapter2/18_Type_Casting.md)
* [嵌套类型](chapter2/19_Nested_Types.md)
* [扩展](chapter2/20_Extensions.md)
* [协议](chapter2/21_Protocols.md)
* [泛型](chapter2/22_Generics.md)
* [不透明类型](chapter2/27_Opaque_Types.md)
* [自动引用计数](chapter2/23_Automatic_Reference_Counting.md)
* [内存安全](chapter2/24_Memory_Safety.md)
* [访问控制](chapter2/25_Access_Control.md)
* [高级运算符](chapter2/26_Advanced_Operators.md)
* [基础部分](02_language_guide/01_The_Basics.md)
* [基本运算符](02_language_guide/02_Basic_Operators.md)
* [字符串和字符](02_language_guide/03_Strings_and_Characters.md)
* [集合类型](02_language_guide/04_Collection_Types.md)
* [控制流](02_language_guide/05_Control_Flow.md)
* [函数](02_language_guide/06_Functions.md)
* [闭包](02_language_guide/07_Closures.md)
* [枚举](02_language_guide/08_Enumerations.md)
* [类和结构体](02_language_guide/09_Structures_And_Classes.md)
* [属性](02_language_guide/10_Properties.md)
* [方法](02_language_guide/11_Methods.md)
* [下标](02_language_guide/12_Subscripts.md)
* [继承](02_language_guide/13_Inheritance.md)
* [构造过程](02_language_guide/14_Initialization.md)
* [析构过程](02_language_guide/15_Deinitialization.md)
* [可选链](02_language_guide/16_Optional_Chaining.md)
* [错误处理](02_language_guide/17_Error_Handling.md)
* [类型转换](02_language_guide/18_Type_Casting.md)
* [嵌套类型](02_language_guide/19_Nested_Types.md)
* [扩展](02_language_guide/20_Extensions.md)
* [协议](02_language_guide/21_Protocols.md)
* [泛型](02_language_guide/22_Generics.md)
* [不透明类型](02_language_guide/23_Opaque_Types.md)
* [自动引用计数](02_language_guide/24_Automatic_Reference_Counting.md)
* [内存安全](02_language_guide/25_Memory_Safety.md)
* [访问控制](02_language_guide/26_Access_Control.md)
* [高级运算符](02_language_guide/27_Advanced_Operators.md)
* 语言参考
* [关于语言参考](chapter3/01_About_the_Language_Reference.md)
* [词法结构](chapter3/02_Lexical_Structure.md)
* [类型](chapter3/03_Types.md)
* [表达式](chapter3/04_Expressions.md)
* [语句](chapter3/05_Statements.md)
* [声明](chapter3/06_Declarations.md)
* [特性](chapter3/07_Attributes.md)
* [模式](chapter3/08_Patterns.md)
* [泛型参数](chapter3/09_Generic_Parameters_and_Arguments.md)
* [语法总结](chapter3/10_Summary_of_the_Grammar.md)
* [关于语言参考](03_language_reference/01_About_the_Language_Reference.md)
* [词法结构](03_language_reference/02_Lexical_Structure.md)
* [类型](03_language_reference/03_Types.md)
* [表达式](03_language_reference/04_Expressions.md)
* [语句](03_language_reference/05_Statements.md)
* [声明](03_language_reference/06_Declarations.md)
* [特性](03_language_reference/07_Attributes.md)
* [模式](03_language_reference/08_Patterns.md)
* [泛型参数](03_language_reference/09_Generic_Parameters_and_Arguments.md)
* [语法总结](03_language_reference/10_Summary_of_the_Grammar.md)
* 翻译贡献者
* [翻译贡献者](contributors.md)

View File

@ -1,11 +0,0 @@
# 版本兼容性
本书描述的是在 Xcode 11 中的默认 Swift 版本 Swift 5.1。你可以使用 Xcode11 来构建 Swift 5.1、Swift 4.2 或 Swift 4 写的项目。
当您使用 Xcode 11 构建 Swift 4 和 Swift 4.2 代码时,除了下面的功能仅支持 Swift 5.1,其他大多数功能都依然可用。
* 返回值是不透明类型的函数依赖 Swift 5.1 运行时。
* **try?** 表达式不会为已返回可选类型的代码引入额外的可选类型层级。
* 大数字的整型字面量初始化代码的类型将会被正确推导,例如 **UInt64(0xffff_ffff_ffff_ffff)** 将会被推导为整型类型而非溢出。
用 Swift 5.1 写的项目可以依赖用 Swift 4.2 或 Swift 4 写的项目反之亦然。这意味着如果你将一个大的项目分解成多个框架framework你可以每次一个框架地迁移 Swift 4 代码到 Swift 5.1。

View File

@ -1,267 +0,0 @@
# Swift 文档修订历史
### 2019-06-03
* 更新至 Swift 5.1。
* 在 [不透明类型](../chapter2/27_Opaque_Types.md) 篇章中新增了有关函数返回值遵循指定协议,而不需要提供指定返回类型的内容。
* 新增 [隐式返回的函数](../chapter2/06_Functions.md#functions-with-an-implicit-return) 和 [简化 Getter 声明](../chapter2/10_Properties.md#shorthand-getter-declaration) 章节,其中包含函数省略 `return` 的内容。
* 在 [类型下标](../chapter2/12_Subscripts.md#type-subscripts) 章节中新增有关在类型中使用下标的内容。
* 更新 [结构体的逐一成员构造器](../chapter2/14_Initialization.md#memberwise-initializers-for-structure-types) 章节,现在逐一成员构造器支持在属性有默认值时省略形参。
* 在 [动态查找成员](../chapter3/07_Attributes.md#dynamicmemberlookup) 章节中新增了有关在运行时用 key path 查找动态成员的内容。
* 更新 [自身类型](../chapter3/03_Types.md#self-type-h) 章节,现在 `Self` 可以指向当前类,结构体或者枚举声明时的类型。
### 2019-03-25
* 更新至 Swift 5。
* 新增 [拓展字符串分隔符](../chapter2/03_Strings_And_Characters.md#extended-string-delimiters) 章节。更新 [字符串字面量](../chapter3/03_Lexical_Structure.md#string-literal) 章节,拓展有关字符串分隔符的内容。
* 新增 [动态调用](../chapter3/07_Attributes.md#dynamiccallable) 章节,其中包含使用 `dynamicCallable` 属性动态调用实例作为函数的内容。
* 新增 [unknown](../chapter3/07_Attributes.md#unknown) 和 [未来枚举匹配](../chapter3/05_Statements.md#future-case2) 章节,其中包含了使用 `unknown` 来处理未来枚举可能发生改变的情形。
* 在 [Key-Path 表达式](../chapter3/04_Expressions.md#key-path-expression) 章节新增了有关标示 key path (\\.self) 的内容。
* 在 [可选编译块](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节新增了有关小于比较符 `<` 的内容。
### 2018-09-17
* 更新至 Swift 4.2。
* 在 [遍历枚举情形](../chapter2/08_Enumerations.md#iterating-over-enumeration-cases) 章节新增了有关访问所有枚举情形的内容。
* 在 [编译诊断](../chapter3/05_Statements.md#compile-time-diagnostic-statement) 章节新增了有关 `#error``#warning` 的内容。
* 在 [属性声明](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `inlinable``usableFromInline` 属性的内容。
* 在 [属性声明](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `requires_stored_property_inits``warn_unqualified_access` 属性的内容。
* 在 [可选编译块](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节新增了有关如何根据 Swift 编译器版本对代码进行对应编译处理的内容。
* 在 [字面量语法](../chapter3/04_Expressions.md#literal-expression) 章节新增了有关 `#dsohandle` 的内容。
### 2018-03-29
* 更新至 Swift 4.1。
* 在 [等价运算符](../chapter2/26_Advanced_Operators.md#equivalence-operators) 章节新增了有关等价运算符的合成实现的内容。
* 在 [声明](../chapter3/06_Declarations.md) 篇章中 [申明拓展](../chapter3/06_Declarations.md#extension-declaration) 章节和 [协议](../chapter2/21_Protocols.md) 篇章中 [有条件地遵循协议](../chapter2/21_Protocols.md#Conditionally-Conforming-to-a-Protocol) 章节新增了有关协议有条件遵循的内容。
* 在 [关联类型约束中使用协议](../chapter2/22_Generics.md#using-a-protocol-in-its-associated-types-constraints) 章节中新增了有关递归协议约束的内容。
* 在 [条件编译块](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节中新增了有关 `canImport()``targetEnvironment()` 平台条件的内容。
### 2017-12-04
* 更新至 Swift 4.0.3。
* 更新 [Key-Path 表达式](../chapter3/04_Expressions.md#key-path-expression) 章节,现在 key path 支持下标子路径。
### 2017-09-19
* 更新至 Swift 4.0。
* 在 [内存安全](../chapter2/24_MemorySafety.md) 章节新增了有关内存互斥访问的内容。
* 新增 [带有泛型 Where 子句联类型](../chapter2/22_Generics.md#associated-types-with-a-generic-where-clause) 章节,现在可以使用泛型 `where` 子句约束关联类型。
* 在 [字符串和字符](../chapter2/03_Strings_And_Characters.md) 篇章中 [字面量](../chapter2/03_Strings_And_Characters.md#string-literals) 章节以及 [词法结构](../chapter3/02_Lexical_Structure.md) 篇章的 [字符串字面量](../chapter3/02_Lexical_Structure.md#string-literal) 章节中新增了有关多行字符串字面量的内容。
* 更新 [声明属性](../chapter3/07_Attributes.md#Ideclaration-attributes) 中 `objc` 属性的讨论,现在该属性会在更少的位置被推断出来。
* 新增 [范型下标](../chapter2/22_Generics.md#generic-subscripts) 章节,现在下标也支持范型特性了。
* 更新 [协议](../chapter2/21_Protocols.md) 篇章中 [协议组合](../chapter2/21_Protocols.md#protocol-composition) 章节和 [类型](../chapter3/03_Types.md) 篇章中 [协议组合类型](../chapter3/03_Types.md#protocol-composition-type-h) 章节的讨论,现在协议组合类型支持进行父类约束了。
* 更新 [拓展声明](../chapter3/06_Declarations.md#extension-declaration) 中有关协议扩展的讨论,现在它们不支持 `final` 特性了。
* 在 [断言和前置条件](../chapter2/01_TheBasics.md#assertions-and-preconditions) 章节中新增了部分前置条件和致命错误的内容。
### 2017-03-27
* 更新至 Swift 3.1。
* 新增 [范型 Where 子句扩展](../chapter2/22_Generics.md#extensions-with-a-generic-where-clause) 章节,包含需要的扩展内容。
* 在 [For-In 循环](../chapter2/05_Control_Flow.md#for-in-loops) 章节中新增了区间迭代的例子。
* 在 [到可失败构造器](http://typora-app/chapter2/14_Initialization.md#failable-initializers) 章节中新增了可失败数值转换的例子。
* 在 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关使用 Swift 语言版本的 `available` 特性的内容 。
* 更新 [函数类型](../chapter3/03_Types.md#function-type-h) 章节中的讨论,注意在写函数类型时不允许使用参数标签。
* 更新 [条件编译块](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节中的 Swift 语言版本号的讨论,现在可以使用可选的补丁版本号。
* 更新 [函数类型](../chapter3/03_Types.md#function-type-h) 章节的讨论,现在 Swift 区分了采用多参数的函数和采用元组类型的单个参数的函数。
* 在 [表达式](../chapter3/04_Expressions.md) 篇章中删除了动态表达式的章节,现在 `type(of:)` 是 Swift 标准库函数。
### 2016-10-27
* 更新至 Swift 3.0.1。
* 更新 [自动引用计数](../chapter2/23_Automatic_Reference_Counting.md) 章节中有关 weak 和 unowned 引用的讨论。
* 在 [声明标识符](../chapter3/06_Declarations.md#declaration-modifiers) 章节中新增了有关新的标识符 `unowned``unowend(safe)``unowned(unsafe)` 的内容。
* 在 [Any 和 AnyObject 的类型转换](../chapter2/18_Type_Casting.md#type-casting-for-any-and-anyobject) 章节中新增了一处说明,有关使用类型 `Any` 作为可选值。
* 更新 [表达式](../chapter3/04_Expressions.md) 章节,把括号表达式和元组表达式的描述分开。
### 2016-09-13
* 更新至 Swift 3.0。
* 更新 [函数](../chapter2/06_Functions.md) 篇章和 [函数声明](../chapter3/06_Declarations.md#function-declaration) 章节中有关函数的讨论,所有函数参数默认都有函数标签。
* 更新 [高级操作符](../chapter2/26_Advanced_Operators.md) 篇章中有关操作符的讨论,现在你可以作为类型函数来实现,替代之前的全局函数实现方式。
* 在 [访问控制](../chapter2/25_Access_Control.md) 章节中新增有关对新的访问级别描述符 `open``fileprivate` 的内容。
* 更新 [函数声明](../chapter3/06_Declarations.md#function-declaration) 章节中有关 `inout` 的讨论,注意它现在出现在参数类型的前面,而不是在参数名称的前面。
* 更新 [逃逸闭包](../chapter2/07_Closures.md#escaping-closures) 和 [自动闭包](../chapter2/07_Closures.md#autoclosures) 章节还有 [属性](../chapter3/07_Attributes.md) 篇章中有关 `@noescape``@autoclosure` 的讨论,现在他们是类型属性,而不是定义属性。
* 在 [高级操作符](../chapter2/26_Advanced_Operators.md) 篇章中 [自定义中缀操作符的优先级](./chapter2/26_Advanced_Operators.md#precedence-and-associativity-for-custom-infix-operators) 章节和 [定义](../chapter3/06_Declarations.md) 篇章中 [优先级组声明](../chapter3/06_Declarations.md#precedence-group-declaration-modifiers) 章节中新增了有关操作符优先级组的内容。
* 更新一些讨论,使用 macOS 替换掉 OS X Error 替换掉 ErrorProtocol。更新一些协议名称比如使用 ExpressibleByStringLiteral 替换掉 StringLiteralConvertible。
* 更新 [泛型](../chapter2/22_Generics.md) 篇章中 [泛型 Where 语句](../chapter2/22_Generics.md#extensions-with-a-generic-where-clause) 章节和 [泛型形参和实参](../chapter3/09_Generic_Parameters_And_Arguments.md) 篇章的讨论,现在泛型的 where 语句写在一个声明的最后。
* 更新 [逃逸闭包](../chapter2/07_Closures.md#escaping-closures) 章节中的讨论,现在闭包默认为非逃逸的。
* 更新 [基础部分](../chapter2/01_TheBasics.md) 篇章中 [可选绑定](../chapter2/01_TheBasics.md#optional-binding) 章节和 [语句](../chapter3/05_Statements.md) 篇章中 [While 语句](../chapter3/05_Statements.md#while-statement) 章节中的讨论,现在 if`while``guard` 语句使用逗号分隔条件列表,不需要使用 `where` 语句。
* 在 [控制流](../chapter2/05_Control_Flow.md) 篇章中 [Switch](../chapter2/05_Control_Flow.md#switch) 章节和 [语句](../chapter3/05_Statements.md) 篇章中 [Switch 语句](../chapter3/05_Statements.md#switch-statement) 章节中新增了 switch cases 可以使用多模式的内容。
* 更新 [函数类型](../chapter3/03_Types.md#function-type-h) 章节有关现在函数参数标签不包含在函数类型中的讨论。
* 更新 [协议](../chapter2/21_Protocols.md) 篇章中 [协议组合](../chapter2/21_Protocols.md#protocol-composition) 章节和 [类型](../chapter3/03_Types.md) 篇章中 [协议组合类型](../chapter3/03_Types.md#protocol-composition-type-h) 章节中有关使用新的 Protocol1 & Protocol2 语法的内容。
* 更新动态类型表达式章节中使用新的 `type(of:)` 表达式的讨论。
* 更新 [行控制表达式](../chapter3/05_Statements.md#line-control-statement) 章节中使用 `#sourceLocation(file:line:)` 表达式的讨论。
* 更新 [永不返回函数](../chapter3/06_Declarations.md#functions-that-never-return) 章节中使用 新的 `Never` 类型的讨论。
* 在 [字面量表达式](../chapter3/04_Expressions.md#literal-expression) 章节中新增了有关 `playground` 字面量的内容。
* 更新 [In-Out 参数](../chapter3/06_Declarations.md#in-out_parameters) 章节,标明只有非逃逸闭包能捕获 `in-out` 参数。
* 更新 [默认参数值](../chapter2/06_Functions.md#default-parameter-values) 章节,现在默认参数不能在调用时候重新排序。
* 更新 [属性](../chapter3/07_Attributes.md) 篇章中有关属性参数使用分号的说明。
* 在 [重新抛出函数和方法](../chapter3/06_Declarations.md#rethrowing-functions-and-methods) 章节中新增了有关在 catch 代码块中抛出错误的重新抛出函数的内容。
* 在 [Selector 表达式](../chapter3/04_Expressions.md#selector-expression7) 章节中新增了中有关访问 Objective-C 中 Selector 的 getter 和 setter 的内容。
* 在 [类型别名声明](../chapter3/06_Declarations.md#type-alias-declaration) 章节中中新增了有关泛型类型别名和在协议内使用类型别名的内容。
* 更新 [函数类型](../chapter3/03_Types.md#function-type-h) 章节中有关函数类型的讨论,标明函数类型作为参数类型必须使用括号包裹。
* 更新 [属性](../chapter3/07_Attributes.md) 篇章,标明 `@IBAction``@IBOutlet``@NSManaged` 隐式含有 `@objc` 属性。
* 在 [声明属性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `@GKInspectable` 的内容。
* 更新 [可选协议要求](../chapter2/21_Protocols.md#optional-protocol-requirements) 章节中有关只能在与 `Objective-C` 交互的代码中才能使用可选协议要求的内容。
* 删除 [函数声明](../chapter3/06_Declarations.md#function-declaration) 章节中有关显式使用 `let` 关键字作为函数参数的内容。
* 删除 [语句](../chapter3/05_Statements.md) 章节中有关 `Boolean` 协议的内容, 现在这个协议已经被 Swift 标准库删除。
* 更正 [声明属性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@NSApplicationMain` 协议的内容。
### 2016-03-21
* 更新至 Swift 2.2。
* 在 [编译配置语句](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节新增了中有关如何根据 Swift 版本进行条件编译。
* 在 [显示成员表达式](../chapter3/04_Expressions.md#explicit-member-expression) 章节中新增了有关如何区分只有参数名不同的方法和构造器的内容。
* 在 [选择器表达式](../chapter3/04_Expressions.md#selector-expression7) 章节中新增了了针对 Objective-C 选择器的 `#selector` 语法。
* 更新 [关联类型](../chapter2/22_Generics.md#associated-types) 和 [协议关联类型声明](../chapter3/06_Declarations.md#protocol_associated_type_declaration) 章节中有关使用 `associatedtype` 关键词修饰关联类型的讨论。
* 更新 [可失败构造器](../chapter2/14_Initialization.md#failable-initializers) 章节中有关当构造器在实例完全初始化之前返回 `nil` 的相关内容。
* 在 [比较运算符](../chapter2/BasicOperators.md#comparison-operators) 章节中新增了比较元组的内容。
* 在 [关键字和标点符号](../chapter3/02_Lexical_Structure.md#keywords-and-punctuation) 章节中新增了使用关键字作为外部参数名的内容。
* 更新 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@objc` 特性的讨论,并指出枚举和枚举用例。
* 更新 [操作符](../chapter3/02_Lexical_Structure.md#operator) 章节中对于自定义运算符的包含了 `.` 的讨论。
* 在 [重新抛出错误的函数和方法](../chapter3/06_Declarations.md#rethrowing-functions-and-methods) 章节中新增了一处说明,重新抛出错误函数不能直接抛出错误。
* 在 [属性观察器](../chapter2/10_Properties.md#property-observers) 章节中新增了一处说明,当作为 in-out 参数传递属性时,属性观察器的调用行为。
* 在 [Swift 初见](./03_a_swift_tour.md) 篇章中新增了错误处理的章节。
* 更新 [弱引用](../chapter2/23_Automatic_Reference_Counting.md#weak-references) 章节中的图片用以更清楚的展示重新分配过程。
* 删除 C 语言风格的 `for` 循环,`++` 前缀和后缀运算符,以及 `--` 前缀和后缀运算符。
* 删除对变量函数参数和柯里化函数的特殊语法的讨论。
### 2015-10-20
* 更新至 Swift 2.1。
* 更新 [字符串插值](../chapter2/03_Strings_And_Characters.md#string-interpolation) 和 [字符串字面量](../chapter3/02_Lexical_Structure.md#string-literal) 章节,现在字符串插值可包含字符串字面量。
* 在 [逃逸闭包](../chapter2/07_Closures.md#escaping-closures) 章节中新增了有关 `@noescape` 属性的相关内容。
* 更新 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 和 [编译配置语句](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节中与 tvOS 相关的内容。
* 在 [In-Out 参数](../chapter3/06_Declarations.md#in-out_parameters) 章节中新增了与 in-out 参数行为相关的内容。
* 在 [捕获列表](../chapter3/04_Expressions.md#capture-lists) 章节新增了有关指定闭包捕获列表被捕获时捕获值的相关内容。
* 更新 [可选链式调用访问属性](../chapter2/16_Optional_Chaining.md#accessing-properties-through-optional-chaining) 章节,阐明了如何通过可选链式调用进行赋值。
* 改进 [自动闭包](../chapter2/07_Closures.md#autoclosures) 章节中对自闭包的讨论。
* 在 [Swift 初见](./03_a_swift_tour.md) 篇章中新增了一个使用 `??` 操作符的例子。
### 2015-09-16
* 更新至 Swift 2.0。
* 在 [错误处理](../chapter2/17_Error_Handling.md) 篇章中新增了有关错误处理的相关内容,包括 [Do 语句](../chapter3/05_Statements.md#do-statement)、 [Throw 语句](../chapter3/05_Statements.md#throw-statement)、 [Defer 语句](../chapter3/05_Statements.md##defer-statements) 以及 [try 运算符](../chapter3/04_Expressions.md#try-operator)。
* 更新 [错误表示和抛出](../chapter2/17_Error_Handling.md#representing-and-throwing-errors) 章节,现在所有类型都可以遵循 `ErrorType` 协议了。
* 在 [将错误装换成可选值](../chapter2/17_Error_Handling.md#converting_errors_to_optional_values) 篇章增加了 `try?` 关键字相关内容。
* 在 [枚举](../chapter2/08_Enumerations.md) 篇章的 [递归枚举](../chapter2/08_Enumerations.md#recursive-enumerations) 章节以及以及 [声明](../chapter3/06_Declarations.md) 篇章的 [任意类型用例的枚举](../chapter3/06_Declarations.md#enumerations-with-cases-of-any-type) 章节中新增了递归枚举相关内容。
* 在 [控制流](../chapter2/05_Control_Flow.md) 篇章的 [API 可用性检查](../chapter2/05_Control_Flow.md#checking-api-availability) 章节和 [语句](../chapter3/05_Statements.md) 篇章的 [可用性条件](../chapter3/05_Statements.md#availability-condition) 章节中新增了有关 API 可用性检查相关的内容。
* 在 [控制流](../chapter2/05_Control_Flow.md) 篇章的 [尽早退出](../chapter2/05_Control_Flow.md#early-exit) 章节和 [语句](../chapter3/05_Statements.md) 篇章的 [Guard 语句](../chapter3/05_Statements.md#guard-statement) 章节新增了与 `guard` 语句相关的内容。
* 在 [协议](../chapter2/21_Protocols.md) 篇章中 [协议扩展](../chapter2/21_Protocols.md#protocol-extensions) 章节中新增了有关协议扩展的内容。
* 在 [访问控制](../chapter2/25_Access_Control.md) 篇章的 [单元测试 target 的访问级别](../chapter2/25_Access_Control.md#access-levels-for-unit-test-targets) 章节中新增了有关单元测试访问控制相关的内容。
* 在 [模式](../chapter3/08_Patterns.md) 篇章的 [可选模式](../chapter3/08_Patterns.md#optional-pattern) 章节中新增了可选模式相关内容。
* 更新 [Repeat-While](../chapter2/05_Control_Flow.md#repeat-while) 章节中有关 `repeat-while` 循环相关的内容。
* 更新 [字符串和字符](../chapter2/03_Strings_And_Characters.md) 章节,现在 `String` 类型在 Swift 标准库中不再遵循 `CollectionType` 协议。
* 在 [常量与变量打印](../chapter2/01_TheBasics.md#printing) 章节中新增了新 Swift 标准库中有关 `print(_:separator:terminator) ` 相关内容。
* 在 [枚举](../chapter2/08_Enumerations.md) 篇章的 [原始值的隐式赋值](../chapter2/08_Enumerations.md#implicitly-assigned-raw-values) 章节和 [声明](../chapter3/06_Declarations.md) 篇章的 [包含原始值类型的枚举](../chapter3/06_Declarations.md#enumerations-with-cases-of-a-raw-value-type) 章节中新增了有关包含 `String` 原始值的枚举用例的行为相关内容。
* 在 [自动闭包](../chapter2/07_Closures.md#autoclosures) 章节中新增了有关 `@autoclosure` 特性的相关内容,包括它的 `@autoclosure(escaping)` 形式。
* 更新 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@avaliable``warn_unused_result` 特性的相关内容。
* 更新 [类型特性](../chapter3/07_Attributes.md#type-attributes) 章节中有关 `@convention` 特性的相关内容。
* 在 [可选绑定](../chapter2/01_TheBasics.md#optional-binding) 章节中新增了有关使用 `where` 子句进行多可选绑定的相关内容。
* 在 [字符串字面量](../chapter3/02_Lexical_Structure.md#string-literal) 章节中新增了有关在编译时使用 `+` 运算符拼接字符串字面量的相关内容。
* 在 [元类型](../chapter3/03_Types.md#metatype-type-h) 章节中新增了有关元类型值的比较和使用它们通过构造器表达式构造实例相关内容。
* 在 [断言调试](../chapter2/01_TheBasics.md#debugging-with-assertions) 章节中新增了一处说明,有关用户定义断言何时会失效。
* 更新 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中对 `@NSManaged` 特性的讨论,现在这个特性可以被应用到一个确定实例方法。
* 更新 [可变参数](../chapter2/06_Functions.md#variadic-parameters) 章节,现在可变参数可以声明在函数参数列表的任意位置中。
* 在 [重写可失败构造器](../chapter2/14_Initialization.md#overriding-a-failable-initializer) 章节中新增了有关非可失败构造器相当于一个可失败构造器通过父类构造器的结果进行强制拆包的相关内容。
* 在 [任意类型用例的枚举](../chapter3/06_Declarations.md#enumerations-with-cases-of-any-type) 章节中新增了有关枚举用例作为函数的内容。
* 在 [构造器表达式](../chapter3/04_Expressions.md#initializer-expression) 章节中新增了有关显式引用一个构造器相关内容。
* 在 [编译控制语句](../chapter3/05_Statements.md#compiler-control-statements) 章节中新增了有关编译内容以及行控制语句相关内容。
* 在 [元类型](../chapter3/03_Types.md#metatype-type-h) 章节新增了一处说明,有关如何从元类型值中构造类实例相关内容。
* 在 [弱引用](../chapter2/23_Automatic_Reference_Counting.md#weak-references) 章节新增了一处说明,有关弱引用作为缓存所存在的不足。
* 更新 [类型特性](../chapter2/10_Properties.md#type-properties) 章节,提到了存储型特性其实是懒加载。
* 更新 [捕获类型](../chapter2/07_Closures.md#capturing_values) 章节,阐明了变量和常量在闭包中如何被捕获。
* 更新 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节,用以描述何时在类中使用 `@objc` 关键字。
* 在 [错误处理](../chapter2/17_Error_Handling.md#handling-errors) 章节中新增了一处说明,有关执行 `throw` 语句的性能。在 [Do 语句](../chapter3/05_Statements.md#do-statement) 章节的 do 语句部分也新增了类似内容。
* 更新 [类型特性](../chapter2/10_Properties.md#type-properties) 章节中有关类、结构体和枚举的存储型和计算型特性相关的内容。
* 更新 [Break 语句](../chapter3/05_Statements.md#break_statement) 章节中有关带标签的 break 语句相关内容。
* 在 [属性观察器](../chapter2/10_Properties.md#property-observers) 章节更新了一处说明,用来明确 `willSet``didSet` 观察器的行为。
* 在 [访问级别](../chapter2/25_Access_Control.md#access-levels) 章节新增了有关 `private` 作用域的相关内容说明。
* 在 [弱引用](../chapter2/23_Automatic_Reference_Counting.md#weak-references) 章节新增了有关弱应用在垃圾回收系统和 ARC 之间的区别的说明。
* 更新 [字符串字面量中特殊字符](../chapter2/03_Strings_And_Characters.md#special-characters-in-string-literals) 章节,对 Unicode 标量更精确定义。
### 2015-04-08
* 更新至 Swift 1.2。
* Swift 现在自身提供了一个 `Set` 集合类型,更多内容,请看 [Sets](../chapter2/CollectionTypes.md#sets) 。
* `@autoclosure` 现在是一个参数声明的属性,而不是参数类型的属性。这里还有一个新的参数声明属性 `@noescape`。更多内容,请看 [属性声明](../chapter3/07_Attributes.md#Ideclaration-attributes) 。
* 对于类型属性和方法现在可以使用 `static` 关键字作为声明描述符,更多内容,请看 [类型变量属性](../chapter3/06_Declarations.md#type-variable-properties)。
* Swift 现在包含一个 `as?``as!` 的向下可失败类型转换运算符。更多内容,请看 [协议遵循性检查](../chapter2/21_Protocols.md#checking-for-protocol-conformance)。
* 新增 [字符串索引](../chapter2/03_Strings_And_Characters.md#string-indices) 的新指导章节。
* 在 [溢出运算符](../chapter2/26_Advanced_Operators.md#overflow-operators) 一节中删除了溢出除运算符(`&/`)和求余溢出运算符(`&%`)。
* 更新常量和常量属性在声明和构造时的规则,更多内容,请看 [常量声明](../chapter3/06_Declarations.md#constant-declaration) 。
* 更新字符串字面量中 Unicode 标量集的定义,请看 [字符串字面量中的特殊字符](../chapter2/03_Strings_And_Characters.md#special-characters-in-string-literals) 。
* 更新 [区间运算符](../chapter2/BasicOperators.md#range-operators) 章节,注意当半开区间运算符含有相同的起止索引时,其区间为空。
* 更新 [闭包引用类型](../chapter2/07_Closures.md#closures-are-reference-types) 章节,对于变量的捕获规则进行了阐明。
* 更新 [值溢出](../chapter2/26_Advanced_Operators.md#value-overflow) 章节,对有符号整数和无符号整数的溢出行为进行了阐明。
* 更新 [协议声明](../chapter3/06_Declarations.md#protocol-declaration) 章节,对协议声明时的作用域和成员等内容进行了阐明。
* 更新 [捕获列表](../chapter2/23_Automatic_Reference_Counting.md#defining-a-capture-list) 章节,对于闭包捕获列表中的弱引用和无主引用的使用语法进行了阐明。
* 更新 [运算符](../chapter3/02_Lexical_Structure.md#operator) 章节明确指明一些例子来说明自定义运算符所支持的特性如数学运算符各种符号Unicode 符号块等。
* 在函数作用域中的常量声明时可以不被初始化,它必须在第一次使用前被赋值。更多的内容,请看 [常量声明](../chapter3/06_Declarations.md#constant-declaration)。
* 在构造器中,常量属性有且仅能被赋值一次。更多内容,请看 [在构造过程中给常量属性赋值](../chapter2/14_Initialization.md{#assigning-constant-properties-during-initialization)。
* 多个可选绑定现在可以在`if`语句后面以逗号分隔的赋值列表的方式出现,更多内容,请看 [可选绑定](../chapter2/01_TheBasics.md#optional-binding)。
* 一个 [可选链表达式](../chapter3/04_Expressions.md#optional-chaining-expression) 必须出现在后缀表达式中。
* 协议类型转换不再局限于 `@obj` 修饰的协议了。
* 在运行时可能会失败的类型转换可以使用 `as?``as!` 运算符,而确保不会失败的类型转换现在使用 `as` 运算符。更多内容,请看 [类型转换运算符](../chapter3/04_Expressions.md#type-casting-operator)。
### 2014-10-16
* 更新至 Swift 1.1。
* 新增 [失败构造器](../chapter2/14_Initialization.md#failable-initializers) 的完整指引。
* 在协议中新增了 [失败构造器要求](../chapter2/21_Protocols.md#failable-initializer-requirements) 的描述。
* 常量和变量的 `Any` 类型现可以包含函数实例。更新了有关 `Any` 相关的示例来展示如何在 `switch` 语句中如何检查并转换到一个函数类型。
* 带有原始值的枚举类型增加了一个 `rawValue` 属性替代 `toRaw()` 方法,同时使用了一个以 `rawValue` 为参数的失败构造器来替代 `fromRaw()` 方法。更多的内容,请看 [原始值](../chapter2/08_Enumerations.md#raw-values) 和 [带原始值的枚举类型](../chapter3/06_Declarations.md#enumerations-with-cases-of-a-raw-value-type)。
* 新增 [Failable Initializer](../chapter3/06_Declarations.md#failable-initializers) 的参考章节,它可以触发初始化失败。
* 自定义运算符现在可以包含 `?` 字符,更新了 [运算符](../chapter3/02_Lexical_Structure.md#operator) 涉及改进后的规则的部分,并且在 [自定义运算符](../chapter2/26_Advanced_Operators.md#custom-operators) 章节中删除了重复的运算符有效字符集合。
### 2014-08-18
* 描述 Swift 1.0 的新文档。Swift 是苹果公司发布的全新编程语言,用于 iOS 和 OS X 应用开发。
* 在协议中新增了 [对构造器的规定](../chapter2/21_Protocols.md#initializer-requirements) 章节。
* 新增 [类专属协议](../chapter2/21_Protocols.md#class-only-protocol) 章节。
* [断言](../chapter2/01_TheBasics.md#assertions-and-preconditions) 现在可以使用字符串内插语法,并删除了文档中有冲突的注释。
* 更新 [连接字符串和字符](../chapter2/03_Strings_And_Characters.md#concatenating-strings-and-characters) 章节来说明字符串和字符不能再用 `+` 号运算符或者复合加法运算符 `+=` 相互连接,这两种运算符现在只能用于字符串之间相连。请使用 `String` 类型的 `append` 方法在一个字符串的尾部增加单个字符。
* 在 [属性申明](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节增加了有关 `availability` 特性的一些内容。
* [可选类型](../chapter2/01_TheBasics.md#optionals) 若有值时,不再隐式的转换为 `true`,同样,若无值时,也不再隐式的转换为 `false`,这是为了避免在判别 optional `Bool` 的值时产生困惑。 替代的方案是,用`==``!=` 运算符显式地去判断 Optinal 是否是 `nil`,以确认其是否包含值。
* Swift 新增了一个 [Nil 合并运算符](../chapter2/BasicOperators.md#nil-coalescing-operator) (`a ?? b`) , 该表达式中,如果 Optional `a` 的值存在,则取得它并返回,若 Optional `a``nil`,则返回默认值 `b`
* 更新和扩展 [字符串的比较](../chapter2/03_Strings_And_Characters.md#comparing-strings) ,用以反映和展示'字符串和字符的比较',以及'前缀prefix/后缀postfix比较'都开始基于扩展字符集extended grapheme clusters规范的等价比较。
* 现在,你可以通过下标赋值或者 [可选调用链](../chapter2/16_Optional_Chaining.md) 中的可变方法和操作符来给属性设值。相应地更新了有关 [通过可选链接访问属性](../chapter2/16_Optional_Chaining.md#accessing-properties-through-optional-chaining) 的内容,并扩展了 [通过可选链接调用方法](../chapter2/16_Optional_Chaining.md#calling-methods-through-optional-chaining) 时检查方法调用成功的示例,以显示如何检查属性设置是否成功。
* 在可选链中新增了 [访问可选类型的下标脚注](../chapter2/16_Optional_Chaining.md#accessing-subscripts-through-optional-chaining) 章节。
* 更新 [访问和修改数组](../chapter2/CollectionTypes.md#accessing-and-modifying-a-dictionary) 章节以标示,从该版本起,不能再通过 `+=` 运算符给一个数组新增一个新的项。对应的替代方案是,使 `append` 方法,或者通过 `+=` 运算符来新增一个只有一个项的数组。
* 新增一处说明,在 [范围运算符](../chapter2/BasicOperators.md#range-operators) 中,比如, `a..b``a..<b` ,起始值 `a` 不能大于结束值 `b`
* 重写 [继承](../chapter2/13_Inheritance.md) 篇章删除了本章中有关构造器重写的介绍性报道转而将更多的注意力放到新增的部分——子类的新功能以及如何通过重写overrides修改已有的功能。另外 [重写属性的 Getters 和 Setters](../chapter2/13_Inheritance.md#overriding-property-etters-and-setters) 中的例子已经被替换为展示如何重写一个 `description` 属性。 (而有关如何在子类的构造器中修改继承属性的默认值的例子,已经被移到 [构造过程](../chapter2/14_Initialization.md) 篇章。)
* 更新 [构造器的继承与重写](../chapter2/14_Initialization.md#initializer-inheritance-and-overriding) 章节以标示: 重写一个特定的构造器必须使用 `override` 修饰符。
* 更新 [Required 构造器](../chapter2/14_Initialization.md#required-initializers) 章节以标示:`required` 修饰符现在需要出现在所有子类的 required 构造器的声明中,而 required 构造器的实现,现在可以仅从父类自动继承。
* 中置Infix的 [运算符函数](../chapter2/26_Advanced_Operators.md#operator-functions) 不再需要 `@infix` 属性。
* [前置和后置运算符](../chapter2/26_Advanced_Operators.md#prefix-and-postfix-operators) 的 `@prefix``@postfix` 属性,已变更为 `prefix``postfix` 声明修饰符。
* 新增一处说明,在 Prefix 和 postfix 运算符被作用于同一个操作数时 [前置和后置运算符](../chapter2/26_Advanced_Operators.md#prefix-and-postfix-operators) 的执行顺序。
* [组合赋值运算符](../chapter2/26_Advanced_Operators.md#compound-assignment-operators) 的运算符函数不再使用 `@assignment` 属性来定义函数。
* 在定义 [自定义操作符](../chapter2/26_Advanced_Operators.md#custom-operators) 时,`修饰符Modifiers的出现顺序发生变化`。比如现在,你该编写 `prefix operator` 而不是 `operator prefix`
* 在 [声明修饰符](../chapter3/06_Declarations.md#declaration-modifiers) 章节新增了有关 `dynamic` 声明修饰符的内容。
* 新增有关 [字面量](../chapter3/02_Lexical_Structure.md#literal) 类型推导内容的内容。
* 新增更多有关柯里化函数的内容。
* 新增 [权限控制](../chapter2/25_Access_Control.md) 篇章。
* 更新 [字符串和字符](../chapter2/03_Strings_And_Characters.md) 章节,在 Swift 中现在 `Character` 类型代表的是扩展字符集extended grapheme cluster中的一个 Unicode为此新增了 [Extended Grapheme Clusters](../chapter2/03_Strings_And_Characters.md#extended-grapheme-clusters) 章节。同时,[Unicode 标量](../chapter2/03_Strings_And_Characters.md#unicode-scalars-representation) 和 [字符串比较](../chapter2/03_Strings_And_Characters.md#comparing-strings) 章节新增了更多内容。
* 更新 [字符串字面量](../chapter2/03_Strings_And_Characters.md#string-literals) 章节在一个字符串中Unicode 标量Unicode scalars`\u{n}`的形式来表示,`n` 是一个最大可以有8位的16进制数。
* `NSString` `length` 属性已被映射到 Swift 的内建 `String`类型。(注意,这两属性的类型是`utf16Count`,而非 `utf16count`)。
* Swift 的内建 `String` 类型不再拥有 `uppercaseString``lowercaseString` 属性。在 [字符串和字符](../chapter2/03_Strings_And_Characters.md) 章节中删除了对应部分,并更新了各种对应的代码用例。
* 新增 [没有外部名的构造器参数](../chapter2/14_Initialization.md#initializer-parameters-without-external-names) 章节。
* 新增 [Required 构造器](../chapter2/14_Initialization.md#required-initializers) 章节。
* 新增 [可选元组返回类型](../chapter2/06_Functions.md#optional-tuple-return-types) 章节。
* 更新 [类型注解](../chapter2/01_TheBasics.md#type-annotations) 章节,多个相关变量可以用"类型注解”在同一行中声明为同一类型。
* `@optional`, `@lazy`, `@final`, `@required` 等关键字被更新为 `optional`, `lazy`, `final`, `required` 参见 [声明修饰符](../chapter3/06_Declarations.md#declaration-modifiers)。
* 更新了整本书中有关 `..<` 的引用,从半闭区间改为了 [半开区间](../chapter2/BasicOperators.md#half-open-range-operator)。
* 更新 [读取和修改字典](../chapter2/CollectionTypes.md#accessing-and-modifying-a-dictionary) 章节, `Dictionary` 现在增加了一个 Boolean 型的属性:`isEmpty`
* 解释了哪些字符(集)可被用来定义 [自定义操作符](../chapter2/26_Advanced_Operators.md#custom-operators)。
* `nil` 和布尔运算中的 `true``false` 现在被定义为 [字面量](../chapter3/02_Lexical_Structure.md#literal)。
* Swift 中的数组 `Array` 类型从现在起具备了完整的值语义。具体内容被更新到 [集合的可变性](../chapter2/CollectionTypes.md#mutability-of-collections) 和 [数组](../chapter2/CollectionTypes.md#arrays) 两小节,以反映这个新的变化。 此外,还解释了如何给 Strings, Arrays 和 Dictionaries 进行赋值和拷贝。
* [数组类型速记语法](../chapter2/CollectionTypes.md#array-type-shorthand-syntax) 从 `SomeType []` 更新为 ` [SomeType]`
* 新增 [字典类型的速记语法](../chapter2/CollectionTypes.md#dictionary-type-shorthand-syntax) 章节,现在书写格式为: ` [KeyType: ValueType]`
* 新增 [字典键类型的哈希值](../chapter2/CollectionTypes.md#hash-values-for-set-types) 章节。
* [闭包表达式](../chapter2/07_Closures.md#closure-expressions) 示例中使用新的全局函数 `sorted` 取代原先的全局函数 `sort` 去展示如何返回一个全新的数组。
* 更新 [结构体逐一成员构造器](../chapter2/14_Initialization.md#memberwise-initializers-for-structure-types) 章节,即使结构体的成员 `没有默认值`,逐一成员构造器也可以自动获得。
* [半开区间运算符](../chapter2/BasicOperators.md#half-open-range-operator) 中`..` 更新为 `..<`
* 新增 [泛型拓展](../chapter2/22_Generics.md#extending-a-generic-type) 的示例。

View File

@ -1,630 +0,0 @@
# 词法结构Lexical Structure
Swift 的*“词法结构lexical structure”* 描述了能构成该语言中有效符号token的字符序列。这些合法符号组成了语言中最底层的构建基块并在之后的章节中用于描述语言的其他部分。一个合法符号由一个标识符identifier、关键字keyword、标点符号punctuation、字面量literal或运算符operator组成。
通常情况下,通过考虑输入文本当中可能的最长子串,并且在随后将介绍的语法约束之下,根据随后将介绍的语法约束生成的,根据 Swift 源文件当中的字符来生成相应的“符号”。这种方法称为*“最长匹配longest match”*,或者*“最大适合maximal munch”*。
## 空白与注释 {#whitespace}
空白whitespace有两个用途分隔源文件中的符号以及帮助区分运算符属于前缀还是后缀参见 [运算符](#operators)在其他情况下空白则会被忽略。以下的字符会被当作空白空格U+0020、换行符U+000A、回车符U+000D、水平制表符U+0009、垂直制表符U+000B、换页符U+000C以及空字符U+0000
注释被编译器当作空白处理。单行注释由 `//` 开始直至遇到换行符U+000A或者回车符U+000D。多行注释由 `/*` 开始,以 `*/` 结束。注释允许嵌套,但注释标记必须匹配。
> 空白语法
>
> *空白* → [*空白项*](#whitespace-item) [*空白*](#whitespace)<sub>可选</sub>
>
#### whitespace-item {#whitespace-item}
>
> *空白项* → [*断行符*](#line-break)
>
> *空白项* → [*注释*](#comment)
>
> *空白项* → [*多行注释*](#multiline-comment)
>
> *空白项* → U+0000U+0009U+000BU+000C 或者 U+0020
>
>
#### line-break {#line-break}
>
> *断行符* → U+000A
>
> *断行符* → U+000D
>
> *断行符* → U+000D 接着是 U+000A
>
>
#### comment {#comment}
>
> *注释* → // [*注释内容*](#comment-text) [断行符*](#line-break)
>
>
#### multiline-comment {#multiline-comment}
>
> *多行注释* → `/*` [*多行注释内容*](#multiline-commnet-text) `*/`
>
>
#### comment-text {#comment-text}
>
> *注释内容* → [*注释内容项*](#comment-text-item) [*注释内容*](#comment-text)<sub>可选</sub>
>
>
#### comment-text-item {#comment-text-item}
>
> *注释内容项* → 任何 Unicode 标量值, 除了 U+000A 或者 U+000D
>
>
#### multiline-commnet-text {#multiline-commnet-text}
>
> *多行注释内容* → [*多行注释内容项*](#multiline-comment-text-item) [*多行注释内容*](#multiline-comment-text)<sub>可选</sub>
>
> *多行注释内容项* → [*多行注释*](#multiline-comment).
>
> *多行注释内容项* → [*注释内容项*](#comment-text-item)
>
> *多行注释内容项* → 任何 Unicode 标量值, 除了 `/*` 或者 `*/`
## 标识符 {#identifiers}
*标识符identifier* 可以由以下的字符开始:大写或小写的字母 `A``Z`、下划线(`_`、基本多文种平面Basic Multilingual Plane中非字符数字组合的 Unicode 字符以及基本多文种平面以外的非个人专用区字符。在首字符之后,允许使用数字和组合 Unicode 字符。
使用保留字作为标识符,需要在其前后增加反引号(`` ` ``)。例如,`class` 不是合法的标识符,但可以使用 `` `class` ``。反引号不属于标识符的一部分,`` `x` `` 和 `x` 表示同一标识符。
闭包中如果没有明确指定参数名称,参数将被隐式命名为 `$0`、`$1`、`$2` 等等。这些命名在闭包作用域范围内是合法的标识符。
> 标识符语法
>
> *标识符* → [*头部标识符*](#identifier-head) [*标识符字符组*](#identifier-characters)<sub>可选</sub>
>
> *标识符* → \`[*头部标识符*](#identifier-head) [*标识符字符组*](#identifier-characters)<sub>可选</sub>\`
>
> *标识符* → [*隐式参数名*](#implicit-parameter-name)
>
> *标识符列表* → [*标识符*](#identifier) | [*标识符*](#identifier) **,** [*标识符列表*](#identifier)
>
>
#### identifier-head {#identifier-head}
>
> *头部标识符* → 大写或小写字母 A - Z
>
> *头部标识符* → _
>
> *头部标识符* → U+00A8U+00AAU+00ADU+00AFU+00B2U+00B5或者 U+00B7U+00BA
>
> *头部标识符* → U+00BCU+00BEU+00C0U+00D6U+00D8U+00F6或者 U+00F8U+00FF
>
> *头部标识符* → U+0100U+02FFU+0370U+167FU+1681U+180D或者 U+180FU+1DBF
>
> *头部标识符* → U+1E00U+1FFF
>
> *头部标识符* → U+200BU+200DU+202AU+202EU+203FU+2040U+2054或者 U+2060U+206F
>
> *头部标识符* → U+2070U+20CFU+2100U+218FU+2460U+24FF或者 U+2776U+2793
>
> *头部标识符* → U+2C00U+2DFF 或者 U+2E80U+2FFF
>
> *头部标识符* → U+3004U+3007U+3021U+302FU+3031U+303F或者 U+3040U+D7FF
>
> *头部标识符* → U+F900U+FD3DU+FD40U+FDCFU+FDF0U+FE1F或者 U+FE30U+FE44
>
> *头部标识符* → U+FE47U+FFFD
>
> *头部标识符* → U+10000U+1FFFDU+20000U+2FFFDU+30000U+3FFFD或者 U+40000U+4FFFD
>
> *头部标识符* → U+50000U+5FFFDU+60000U+6FFFDU+70000U+7FFFD或者 U+80000U+8FFFD
>
> *头部标识符* → U+90000U+9FFFDU+A0000U+AFFFDU+B0000U+BFFFD或者 U+C0000U+CFFFD
>
> *头部标识符* → U+D0000U+DFFFD 或者 U+E0000U+EFFFD
>
> *标识符字符* → 数值 0 - 9
>
>
#### identifier-character {#identifier-character}
>
> *标识符字符* → U+0300U+036FU+1DC0U+1DFFU+20D0U+20FF或者 U+FE20U+FE2F
>
> *标识符字符* → [*头部标识符*](#identifier-head)
>
>
#### identifier-characters {#identifier-characters}
>
> *标识符字符组* → [*标识符字符*](#identifier-character) [*标识符字符组*](#identifier-characters)<sub>可选</sub>
>
>
#### implicit-parameter-name {#implicit-parameter-name}
>
> *隐式参数名* → **$** [*十进制数字列表*](#decimal-digit)
## 关键字和标点符号 {#keywords-and-punctuation}
下面这些被保留的关键字不允许用作标识符,除非使用反引号转义,具体描述请参考 [标识符](#identifiers)。除了 `inout``var` 以及 `let` 之外的关键字可以用作某个函数声明或者函数调用当中的外部参数名,无需添加反引号转义。当一个成员与一个关键字具有相同的名称时,不需要使用反引号来转义对该成员的引用,除非在引用该成员和使用该关键字之间存在歧义 - 例如,`self``Type``Protocol` 在显式的成员表达式中具有特殊的含义,因此它们必须在该上下文中使用反引号进行转义。
* 用在声明中的关键字: `associatedtype``class``deinit``enum``extension``fileprivate ``func``import``init``inout``internal``let``open``operator``private``protocol``public``static``struct``subscript``typealias` 以及 `var`
* 用在语句中的关键字:`break``case``continue``default``defer``do``else``fallthrough``for``guard``if``in``repeat``return``switch``where` 以及 `while`
* 用在表达式和类型中的关键字:`as``Any``catch``false``is``nil``rethrows``super``self``Self``throw``throws``true` 以及 `try `
* 用在模式中的关键字:`_`
* 以井字号(`#`)开头的关键字:`#available``#colorLiteral``#column``#else``#elseif``#endif``#error``#file``#fileLiteral``#function``#if``#imageLiteral ``#line``#selector``#sourceLocation`以及 `#warning`
* 特定上下文中被保留的关键字: `associativity``convenience``dynamic``didSet``final``get``infix``indirect``lazy``left``mutating``none``nonmutating``optional``override``postfix``precedence``prefix``Protocol``required``right``set``Type``unowned``weak` 以及 `willSet`。这些关键字在特定上下文之外可以被用做标识符。
以下符号被当作保留符号,不能用于自定义运算符: `(``)``{``}``[``]``.``,``:``;``=``@``#``&`(作为前缀运算符)、`->`、`` ` ``、`?`、`!`(作为后缀运算符)。
## 字面量 {#literal}
*字面量literal* 用来表示源码中某种特定类型的值,比如一个数字或字符串。
下面是字面量的一些示例:
```swift
42 // 整数字面量
3.14159 // 浮点数字面量
"Hello, world!" // 字符串字面量
true // 布尔值字面量
```
字面量本身并不包含类型信息。事实上,一个字面量会被解析为拥有无限的精度,然后 Swift 的类型推导会尝试去推导出这个字面量的类型。比如,在 `let x: Int8 = 42` 这个声明中Swift 使用了显式类型注解(`: Int8`)来推导出 `42` 这个整数字面量的类型是 `Int8`。如果没有可用的类型信息, Swift 则会从标准库中定义的字面量类型中推导出一个默认的类型。整数字面量的默认类型是 `Int`,浮点数字面量的默认类型是 `Double`,字符串字面量的默认类型是 `String`,布尔值字面量的默认类型是 `Bool`。比如,在 `let str = "Hello, world"` 这个声明中,字符串 `"Hello, world"` 的默认推导类型就是 `String`。
当为一个字面量值指定了类型注解的时候,这个标注的类型必须能通过这个字面量值实例化。也就是说,这个类型必须符合这些 Swift 标准库协议中的一个:整数字面量的 `IntegerLiteralConvertible` 协议、浮点数字面量的 `FloatingPointLiteralConvertible` 协议、字符串字面量的 `StringLiteralConvertible` 协议以及布尔值字面量的 `BooleanLiteralConvertible` 协议。比如,`Int8` 符合 `IntegerLiteralConvertible` 协议,因此它能在 `let x: Int8 = 42` 这个声明中作为整数字面量 `42` 的类型注解。
> 字面量语法
>
> *字面量* → [*数值字面量*](#integer-literal) | [*字符串字面量*](#string-literal) | [*布尔值字面量*](#integer-literal) | [*nil 字面量*](#integer-literal)
>
> *数值字面量* → **-**<sub>可选</sub> [*整数字面量*](#integer-literal) | **-**<sub>可选</sub> [*浮点数字面量*](#floating-point-literal)
>
> *布尔值字面量* → **true** | **false**
>
> *nil 字面量* → **nil**
### 整数字面量{#integer-literal}
*整数字面量Integer Literals* 表示未指定精度整数的值。整数字面量默认用十进制表示,可以加前缀来指定其他的进制。二进制字面量加 `0b`,八进制字面量加 `0o`,十六进制字面量加 `0x`。
十进制字面量包含数字 `0` 至 `9`。二进制字面量只包含 `0` 或 `1`,八进制字面量包含数字 `0` 至 `7`,十六进制字面量包含数字 `0` 至 `9` 以及字母 `A` 至 `F`(大小写均可)。
负整数的字面量在整数字面量前加负号 `-`,比如 `-42`。
整型字面面可以使用下划线(`_`)来增加数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,这同样也会被系统所忽略,并不会影响字面量的值。
除非特别指定,整数字面量的默认推导类型为 Swift 标准库类型中的 `Int`。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 [整数](../chapter2/01_The_Basics.md#integers)。
> 整数字面量语法
>
>
#### integer-literal {#integer-literal}
>
> *整数字面量* → [*二进制字面量*](#binary-literal)
>
> *整数字面量* → [*八进制字面量*](#octal-literal)
>
> *整数字面量* → [*十进制字面量*](#decimal-literal)
>
> *整数字面量* → [*十六进制字面量*](#hexadecimal-literal)
>
>
#### binary-literal {#binary-literal}
>
> *二进制字面量* → **0b** [*二进制数字*](#binary-digit) [*二进制字面量字符组*](#binary-literal-characters)<sub>可选</sub>
>
>
#### binary-digit {#binary-digit}
>
> *二进制数字* → 数值 0 到 1
>
> *二进制字面量字符* → [*二进制数字*](#binary-digit) | _
>
>
#### binary-literal-characters {#binary-literal-characters}
>
> *二进制字面量字符组* → [*二进制字面量字符*](#binary-literal-character) [*二进制字面量字符组*](#binary-literal-characters)<sub>可选</sub>
>
>
#### octal-literal {#octal-literal}
>
> *八进制字面量* → **0o** [*八进字数字*](#octal-digit) [*八进制字符组*](#octal-literal-characters)<sub>可选</sub>
>
>
#### octal-digit {#octal-digit}
>
> *八进字数字* → 数值 0 到 7
>
> *八进制字符* → [*八进字数字*](#octal-digit) | _
>
>
#### octal-literal-characters {#octal-literal-characters}
>
> *八进制字符组* → [*八进制字符*](#octal-literal-character) [*八进制字符组*](#octal-literal-characters)<sub>可选</sub>
>
>
#### decimal-literal {#decimal-literal}
>
> *十进制字面量* → [*十进制数字*](#decimal-digit) [*十进制字符组*](#decimal-literal-characters)<sub>可选</sub>
>
>
#### decimal-digit {#decimal-digit}
>
> *十进制数字* → 数值 0 到 9
>
>
#### decimal-literal-characters {#decimal-literal-characters}
>
> *十进制数字组* → [*十进制数字*](#decimal-digit) [*十进制数字组*](#decimal-literal-characters)<sub>可选</sub>
>
> *十进制字符* → [*十进制数字*](#decimal-digit) | _
>
> *十进制字符组* → [*十进制字符*](#decimal-literal-characters) [*十进制字符组*](#decimal-literal-characters)<sub>可选</sub>
>
>
#### hexadecimal-literal {#hexadecimal-literal}
>
> *十六进制字面量* → **0x** [*十六进制数字*](#hexadecimal-digit) [*十六进制字面量字符组*](#hexadecimal-literal-characters)<sub>可选</sub>
>
>
#### hexadecimal-digit {#hexadecimal-digit}
>
> *十六进制数字* → 数值 0 到 9, 字母 a 到 f, 或 A 到 F
>
> *十六进制字符* → [*十六进制数字*](#hexadecimal-digit) | _
>
>
#### hexadecimal-literal-characters {#hexadecimal-literal-characters}
>
> *十六进制字面量字符组* → [*十六进制字符*](#hexadecimal-literal-characters) [*十六进制字面量字符组*](#hexadecimal-literal-characters)<sub>可选</sub>
### 浮点数字面量{#floating-point-literal}
*浮点数字面量Floating-point literals* 表示未指定精度浮点数的值。
浮点数字面量默认用十进制表示(无前缀),也可以用十六进制表示(加前缀 `0x`)。
十进制浮点数字面量由十进制数字串后跟小数部分或指数部分(或两者皆有)组成。十进制小数部分由小数点(`.`)后跟十进制数字串组成。指数部分由大写或小写字母 `e` 为前缀后跟十进制数字串组成,这串数字表示 `e` 之前的数量乘以 10 的几次方。例如:`1.25e2` 表示 1.25 x 10²也就是 `125.0`;同样,`1.25e2` 表示 1.25 x 10¯²也就是 `0.0125`。
十六进制浮点数字面量由前缀 `0x` 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字串组成。指数部分由大写或小写字母 `p` 为前缀后跟十进制数字串组成,这串数字表示 `p` 之前的数量乘以 2 的几次方。例如:`0xFp2` 表示 15 x 2²也就是 `60`;同样,`0xFp-2` 表示 15 x 2¯²也就是 `3.75`。
负数的浮点数字面量由负号(`-`)和浮点数字面量组成,例如 `-42.5`。
浮点数字面量允许使用下划线(`_`)来增强数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,并不会影响字面量的值。
除非特别指定,浮点数字面量的默认推导类型为 Swift 标准库类型中的 `Double`,表示 64 位浮点数。Swift 标准库也定义了 `Float` 类型,表示 32 位浮点数。
> 浮点数字面量语法
>
>
#### floating-point-literal {#floating-point-literal}
>
> *浮点数字面量* → [*十进制字面量*](#decimal-literal) [*十进制分数*](#decimal-fraction)<sub>可选</sub> [*十进制指数*](#decimal-exponent)<sub>可选</sub>
>
> *浮点数字面量* → [*十六进制字面量*](#hexadecimal-literal) [*十六进制分数*](#hexadecimal-fraction)<sub>可选</sub> [*十六进制指数*](#hexadecimal-exponent)
>
>
#### decimal-fraction {#decimal-fraction}
>
> *十进制分数* → **.** [*十进制字面量*](#decimal-literal)
>
>
#### decimal-exponent {#decimal-exponent}
>
> *十进制指数* → [*十进制指数 e*](#floating-point-e) [*正负号*](#sign)<sub>可选</sub> [*十进制字面量*](#decimal-literal)
>
>
#### hexadecimal-fraction {#hexadecimal-fraction}
>
> *十六进制分数* → **.** [*十六进制数字*](#hexadecimal-digit) [*十六进制字面量字符组*](#hexadecimal-literal-characters)<sub>可选</sub>
>
>
#### hexadecimal-exponent {#hexadecimal-exponent}
>
> *十六进制指数* → [*十六进制指数 p*](#floating-point-p) [*正负号*](#sign)<sub>可选</sub> [*十进制字面量*](#decimal-literal)
>
>
#### floating-point-e {#floating-point-e}
>
> *十进制指数 e* → **e** | **E**
>
>
#### floating-point-p {#floating-point-p}
>
> *十六进制指数 p* → **p** | **P**
>
>
#### sign {#sign}
>
> *正负号* → **+** | **-**
### 字符串字面量 {#string-literal}
字符串字面量是被引号包括的一串字符组成。 单行字符串字面量被包在双引号中的一串字符组成,形式如下:
> "`字符`"
字符串字面量中不能包含未转义的双引号(`"`)、未转义的反斜线(`\`)、回车符、换行符。
多行字符串字面量被包在三个双引号中的一串字符组成,形式如下:
> """
> `字符`
> """
与单行字符串字面量不同的是,多行字符串字面量可以包含不转义的双引号("),回车以及换行。它不能包含三个未转义的连续双引号。
""" 之后的回车或者换行开始多行字符串字面量,不是字符串的一部分。 """ 之前回车或者换行结束字面量,也不是字符串的一部分。要让多行字符串字面量的开始或结束带有换行,就在第一行或者最后一行写一个空行。
多行字符串字面量可以使用任何空格或制表符组合进行缩进;这些缩进不会包含在字符串中。 """ 的结束符号决定了缩进:字面量中的任何一个非空行必须起始于多行字符串字面量结束符号的前面;空格和制表符不会被转换。你可以包在缩进后含额外的空格和制表符;这些空格和制表符会在字符串中出现。
多行字符串字面量中的一行结束使用规范化的换行符号。尽管你的源代码混用了回车和换行符,字符串中所有的行结束都必须一样.
在多行字符串字面量里, 在行末用反斜线(`\`)可以省略字符串行间中断。 反斜线之间的空白和行间中断也可以省略。 你可以在你的代码里用这种语法硬包裹多行字符串字面量,不需要改变产生的字符串的值。
可以在字符串字面量中使用的转义特殊符号如下:
* 空字符 `\0`
* 反斜线 `\\`
* 水平制表符 `\t`
* 换行符 `\n`
* 回车符 `\r`
* 双引号 `\"`
* 单引号 `\'`
* Unicode 标量 `\u{`n`}`n 为一到八位的十六进制数字
字符串字面量允许在反斜杠(`\`)后的括号 `()` 中插入表达式的值。插入表达式可以包含字符串字面量,但不能包含未转义的反斜线(`\`)、回车符以及换行符。
例如,以下所有字符串字面量的值都是相同的:
```swift
"1 2 3"
"1 2 \("3")"
"1 2 \(3)"
"1 2 \(1 + 2)"
let x = 3; "1 2 \(x)"
```
可以使用一对或多对扩展分隔符(#)包裹字符串进行分隔,被分隔的字符串的形式如下所示:
> \#"`characters`"#
>
> \#"""
>
> `characters`
>
> """#
特殊字符在被分隔符分隔的结果字符串中会展示为普通字符,而不是特殊字符。你可以使用扩展分隔符来创建一些具有特殊效果的字符串。例如,生成字符串插值,启动或终止转义序列(字符串)。
以下所示,由字符串字面量和扩展分隔符所创建的字符串是等价的:
```swift
let string = #"\(x) \ " \u{2603}"#
let escaped = "\\(x) \\ \" \\u{2603}"
print(string)
// Prints "\(x) \ " \u{2603}"
print(string == escaped)
// Prints "true"
```
如果在一个字符串中使用多对扩展分隔符,请不要在分隔符之间使用空格。
```swift
print(###"Line 1\###nLine 2"###) // OK
print(# # #"Line 1\# # #nLine 2"# # #) // Error
```
使用扩展分隔符创建的多行字符串字面量与普通多行字符串字面量具有相同的缩进要求。
字符串字面量的默认推导类型为 `String`。更多有关 `String` 类型的信息请参考 [字符串和字符](../chapter2/03_Strings_and_Characters.md) 以及 [*字符串结构参考*](https://developer.apple.com/documentation/swift/string)。
`` 操作符连接的字符型字面量是在编译时进行连接的。比如下面的 `textA``textB` 是完全一样的,`textA` 没有任何运行时的连接操作。
```swift
let textA = "Hello " + "world"
let textB = "Hello world"
```
> 字符串字面量语法
>
> *字符串字面量* → [*静态字符串字面量*](#static-string-literal) | [*插值字符串字面量*](#interpolated-string-literal)
>
> *字符串开分隔定界符* → [*字符串扩展分隔符*](#extended-string-literal-delimiter) **"**
>
> *字符串闭分隔定界符* → **"** [*字符串扩展分隔符*](#extended-string-literal-delimiter)<sub>可选</sub>
>
>
#### static-string-literal {#static-string-literal}
>
> *静态字符串字面量* → [*字符串开分隔定界符*](#extended-string-literal-delimiter) [*引用文本*](#quoted-text)<sub>可选</sub> [*字符串闭分隔定界符*](#extended-string-literal-delimiter)
>
> *静态字符串字面量* → [*多行字符串开分隔定界符*](#extended-string-literal-delimiter) [*多行引用文本*](#multiline-quoted-text)<sub>可选</sub> [*多行字符串闭分隔定界符*](#extended-string-literal-delimiter)
>
> *多行字符串开分隔定界符* → [*字符串扩展分隔符*](#extended-string-literal-delimiter) **"""**
>
> *多行字符串闭分隔定界符* → **"""** [*字符串扩展分隔符*](#extended-string-literal-delimiter)
>
>
#### extended-string-literal-delimiter {#extended-string-literal-delimiter}
>
> *字符串扩展分隔符* → **#** [*字符串扩展分隔符*](#extended-string-literal-delimiter)<sub>可选</sub>
>
>
#### quoted-text {#quoted-text}
>
> *引用文本* → [*引用文本项*](#quoted-text-item) [*引用文本*](#quoted-text)<sub>可选</sub>
>
>
#### quoted-text-item {#quoted-text-item}
>
> *引用文本项* → [*转义字符*](#escaped-character)
>
> *引用文本项* → 除了 **"**、**\\**、U+000A、U+000D 以外的所有 Unicode 字符
>
>
#### multiline-quoted-text {#multiline-quoted-text}
>
> *多行引用文本* → [*多行引用文本项*](#multiline-quoted-text-item) [*多行引用文本*](#multiline-quoted-text)<sub>可选</sub>
>
>
#### multiline-quoted-text-item {#multiline-quoted-text-item}
>
> *多行引用文本项* [*转义字符*](#escaped-character)<sub>可选</sub>
>
>
#### multiline-quoted-text {#multiline-quoted-text}
>
> *多行引用文本* → 除了 **\** 以外的任何Unicode标量值
>
> *多行引用文本* → [*转义换行*](#escaped-newline)
>
>
#### interpolated-string-literal {#interpolated-string-literal}
>
> *插值字符串字面量* → [*字符串开分隔定界符*](#extended-string-literal-delimiter) [*插值文本*](#interpolated-text)<sub>可选</sub> [*字符串闭分隔定界符*](#extended-string-literal-delimiter)
>
> *插值字符串字面量* → [*多行字符串开分隔定界符*](#extended-string-literal-delimiter) [*插值文本*](#interpolated-text)<sub>可选</sub> [*多行字符串闭分隔定界符*](#extended-string-literal-delimiter)
>
>
#### interpolated-text {#interpolated-text}
>
> *插值文本* → [*插值文本项*](#interpolated-text-item) [*插值文本*](#interpolated-text)<sub>可选</sub>
>
>
#### interpolated-text-item {#interpolated-text-item}
>
> *插值文本项* → **\\****(**[*表达式*](./04_Expressions.md)**)** | [*引用文本项*](#quoted-text-item)
>
> *多行插值文本* → [*多行插值文本项*](#multiline-quoted-text-item) [*多行插值文本*](#multiline-quoted-text)<sub>可选</sub>
>
> *多行插值文本项* → **\\(** [表达式](./04_Expressions.md) **)** | [多行引用文本项](#multiline-quoted-text-item)
>
>
#### escape-sequence {#escape-sequence}
>
> *转义序列* → **\\** [字符串扩展分隔符](#extended-string-literal-delimiter)
>
>
#### escaped-character {#escaped-character}
>
> *转义字符* → [*转义序列*](#escape-sequence) **0** | [*转义序列*](#escape-sequence) **\\** | [*转义序列*](#escape-sequence) **t** | [*转义序列*](#escape-sequence) **n** | [*转义序列*](#escape-sequence) **r** | [*转义序列*](#escape-sequence) **\"** | [*转义序列*](#escape-sequence) **'**
>
> *转义字符* → [*转义序列*](#escape-sequence) **u {** [*unicode 标量数字*](#unicode-scalar-digits) **}**
>
>
#### unicode-scalar-digits {#unicode-scalar-digits}
>
> *unicode 标量数字* → 一到八位的十六进制数字
>
>
#### escaped-newline {#escaped-newline}
>
> *转义换行符* → [*转义序列*](#escape-sequence) [*空白*](#whitespace)<sub>可选</sub> [*断行符*](#line-break)
## 运算符 {#operator}
Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基础运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/26_Advanced_Operators.md) 中进行了阐述。这一小节将描述哪些字符能用于自定义运算符。
自定义运算符可以由以下其中之一的 ASCII 字符 `/``=``-``+``!``*``%``<``>``&``|``^``?` 以及 `~`,或者后面语法中规定的任一个 Unicode 字符(其中包含了*数学运算符*、*零散符号Miscellaneous Symbols* 以及印刷符号Dingbats之类的 Unicode 块)开始。在第一个字符之后,允许使用组合型 Unicode 字符。
您也可以以点号(`.`)开头来定义自定义运算符。这些运算符可以包含额外的点,例如 `.+.`。如果某个运算符不是以点号开头的,那么它就无法再包含另外的点号了。例如,`+.+` 就会被看作为一个 `+` 运算符后面跟着一个 `.+` 运算符。
虽然您可以用问号 `?` 来自定义运算符,但是这个运算符不能只包含单独的一个问号。此外,虽然运算符可以包含一个惊叹号 `!`,但是前缀运算符不能够以问号或者惊叹号开头。
> 注意
>
> 以下这些标记 `=`、`->`、`//`、`/*`、`*/`、`.`、`<`(前缀运算符)、`&`、`?`、`?`(中缀运算符)、`>`(后缀运算符)、`!` 、`?` 是被系统保留的。这些符号不能被重载,也不能用于自定义运算符。
运算符两侧的空白被用来区分该运算符是否为前缀运算符、后缀运算符或二元运算符。规则总结如下:
* 如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:`a+++b``a +++ b` 当中的 `+++` 运算符会被看作二元运算符。
* 如果运算符只有左侧空白,将被看作一元前缀运算符。例如 `a +++b` 中的 `+++` 运算符会被看做是一元前缀运算符。
* 如果运算符只有右侧空白,将被看作一元后缀运算符。例如 `a+++ b` 中的 `+++` 运算符会被看作是一元后缀运算符。
* 如果运算符左侧没有空白并紧跟 `.`,将被看作一元后缀运算符。例如 `a+++.b` 中的 `+++` 运算符会被视为一元后缀运算符(即上式被视为 `a+++ .b` 而不是 `a +++ .b`)。
鉴于这些规则,运算符前的字符 `(``[``{`,运算符后的字符 `)``]``}`,以及字符 `,``;``:` 都被视为空白。
以上规则需注意一点,如果预定义运算符 `!``?` 左侧没有空白,则不管右侧是否有空白都将被看作后缀运算符。如果将 `?` 用作可选链式调用运算符,左侧必须无空白。如果用于条件运算符 `? :`,必须两侧都有空白。
在某些特定的设计中 ,以 `<``>` 开头的运算符会被分离成两个或多个符号,剩余部分可能会以同样的方式被再次分离。因此,在 `Dictionary<String, Array<Int>>` 中没有必要添加空白来消除闭合字符 `>` 的歧义。在这个例子中, 闭合字符 `>` 不会被视为单独的符号,因而不会被错误解析为 `>>` 运算符。
要学习如何自定义运算符,请参考 [自定义运算符](../chapter2/26_Advanced_Operators.md#custom_operators) 和 [运算符声明](./06_Declarations.md#operator_declaration)。要学习如何重载运算符,请参考 [运算符函数](../chapter2/26_Advanced_Operators.md#operator_functions)。
> 运算符语法
>
> *运算符* → [*头部运算符*](#operator-head) [*运算符字符组*](#operator-characters)<sub>可选</sub>
>
> *运算符* → [*头部点运算符*](#dot-operator-head) [*点运算符字符组*](#dot-operator-characters)
>
>
#### operator-head {#operator-head}
>
> *头部运算符* → **/** | **=** | **-** | **+** | **!** | __*__ | **%** | **<** | **>** | **&** | **|** | **^** | **~** | **?**
>
> *头部运算符* → U+00A1U+00A7
>
> *头部运算符* → U+00A9 或 U+00AB
>
> *头部运算符* → U+00AC 或 U+00AE
>
> *头部运算符* → U+00B0U+00B1U+00B6U+00BBU+00BFU+00D7或 U+00F7
>
> *头部运算符* → U+2016U+2017 或 U+2020U+2027
>
> *头部运算符* → U+2030U+203E
>
> *头部运算符* → U+2041U+2053
>
> *头部运算符* → U+2055U+205E
>
> *头部运算符* → U+2190U+23FF
>
> *头部运算符* → U+2500U+2775
>
> *头部运算符* → U+2794U+2BFF
>
> *头部运算符* → U+2E00U+2E7F
>
> *头部运算符* → U+3001U+3003
>
> *头部运算符* → U+3008U+3030
>
>
#### operator-character {#operator-character}
>
> *运算符字符* → [*头部运算符*](#operator-head)
>
> *运算符字符* → U+0300U+036F
>
> *运算符字符* → U+1DC0U+1DFF
>
> *运算符字符* → U+20D0U+20FF
>
> *运算符字符* → U+FE00U+FE0F
>
> *运算符字符* → U+FE20U+FE2F
>
> *运算符字符* → U+E0100U+E01EF
>
>
#### operator-characters {#operator-characters}
>
> *运算符字符组* → [*运算符字符*](#operator-character) [*运算符字符组*](#operator-characters)<sub>可选</sub>
>
>
#### dot-operator-head {#dot-operator-head}
>
> *头部点运算符* → **..**
>
>
#### dot-operator-character {#dot-operator-character}
>
> *点运算符字符* → **.** | [*运算符字符*](#operator-character)
>
>
#### dot-operator-characters {#dot-operator-characters}
>
> *点运算符字符组* → [*点运算符字符*](#dot-operator-character) [*点运算符字符组*](#dot-operator-characters)<sub>可选</sub>
>
> *二元运算符* → [*运算符*](#operator)
>
> *前缀运算符* → [*运算符*](#operator)
>
> *后缀运算符* → [*运算符*](#operator)

View File

@ -1,419 +0,0 @@
# 特性Attributes
在 Swift 中有两种特性,分别用于修饰声明和类型。特性提供了有关声明和类型的更多信息。例如,使用 `discardableResult` 特性声明的函数,表明该函数虽然有返回值,但如果没有使用该返回值,编译器不会产生警告。
您可以通过以下方式指定一个特性,通过符号 `@` 后跟特性的名称和特性接收的任何参数:
@`特性名`
@`特性名`(`特性参数`)
有些声明特性通过接收参数来指定特性的更多信息以及它是如何修饰某个特定的声明的。这些_特性的参数_写在圆括号内它们的格式由它们所属的特性来定义。
## 声明特性 {#declaration-attributes}
声明特性只能应用于声明。
### `available` {#available}
`available` 特性用于声明时,表示该声明的生命周期是相对于特定的平台和操作系统版本。
`available` 特性经常与参数列表一同出现,该参数列表至少有两个特性参数,参数之间由逗号分隔。这些参数由以下这些平台名字中的一个起头:
- `iOS`
- `iOSApplicationExtension`
- `macOS`
- `macOSApplicationExtension`
- `watchOS`
- `watchOSApplicationExtension`
- `tvOS`
- `tvOSApplicationExtension`
- `swift`
当然,你也可以用一个星号(`*`)来表示上面提到的所有平台。指定 Swift 版本的 `available` 特性参数,不能使用星号表示。
其余的参数,可以按照任何顺序出现,并且可以添加关于声明生命周期的附加信息,包括重要事件。
- `unavailable` 参数表示该声明在指定的平台上是无效的。当指定 Swift 版本可用性时不可使用该参数。
- `introduced` 参数表示指定平台从哪一版本开始引入该声明。格式如下:
`introduced`: `版本号`
*版本号*由一至三个正整数构成,由句点分隔的。
- `deprecated` 参数表示指定平台从哪一版本开始弃用该声明。格式如下:
`deprecated`: `版本号`
可选的*版本号*由一个或多个正整数构成,由句点分隔的。省略版本号表示该声明目前已弃用,当弃用出现时没有给出任何有关信息。如果你省略了版本号,冒号(`:`)也可省略。
- `obsoleted` 参数表示指定平台或语言从哪一版本开始废弃该声明。当一个声明被废弃后,它就从平台或语言中移除,不能再被使用。格式如下:
`obsoleted`: `版本号`
*版本号*由一至三个正整数构成,由句点分隔的。
- `message` 参数用来提供文本信息。当使用被弃用或者被废弃的声明时,编译器会抛出警告或错误信息。格式如下:
`message`: `信息内容`
_信息内容_由一个字符串构成。
- `renamed` 参数用来提供文本信息,用以表示被重命名的声明的新名字。当使用声明的旧名字时,编译器会报错提示新名字。格式如下:
`renamed`: `新名字`
_新名字_由一个字符串构成。
你可以将 `renamed` 参数和 `unavailable` 参数用于 `available` 特性,来表示声明在不同平台和 Swift 版本上的可用性。如下所示,表示声明的名字在一个框架或者库的不同发布版本间发生了变化。以此组合表示该声明被重命名的编译错误。
```swift
// 首发版本
protocol MyProtocol {
// 这里是协议定义
}
```
```swift
// 后续版本重命名了 MyProtocol
protocol MyRenamedProtocol {
// 这里是协议定义
}
@available(*, unavailable, renamed:"MyRenamedProtocol")
typealias MyProtocol = MyRenamedProtocol
```
你可以在某个声明上使用多个 `available` 特性,以指定该声明在不同平台和 Swift 版本上的可用性。编译器只有在与 `available` 特性中指定的平台或语言版本匹配时,才会使用 `available` 特性。
如果 `available` 特性除了平台名称参数外,只指定了一个 `introduced` 参数,那么可以使用以下简写语法代替:
@available(`平台名称` `版本号`, *)
@available(swift `版本号`)
`available` 特性的简写语法可以简明地表达出声明在多个平台上的可用性。尽管这两种形式在功能上是相同的,但请尽可能地使用简写语法形式。
```swift
@available(iOS 10.0, macOS 10.12, *)
class MyClass {
// 这里是类定义
}
```
`available` 特性需要同时指定 Swift 版本和平台可用性,需要使用单独的 `available` 特性来声明。
```swift
@available(swift 3.0.2)
@available(macOS 10.12, *)
struct MyStruct {
// 这里是结构体定义
}
```
### `discardableResult` {#discardableresult}
该特性用于的函数或方法声明,以抑制编译器中函数或方法的返回值被调而没有使用其结果的警告。
### `dynamicCallable` {#dynamiccallable}
该特性用于类、结构体、枚举或协议,以将该类型的实例视为可调用的函数。该类型必须实现 `dynamicallyCall(withArguments:)``dynamicallyCall(withKeywordArguments:)` 方法之一,或两者同时实现。
你可以调用 `dynamicCallable` 特性的实例,就像是调用一个任意数量参数的函数。
```swift
@dynamicCallable
struct TelephoneExchange {
func dynamicallyCall(withArguments phoneNumber: [Int]) {
if phoneNumber == [4, 1, 1] {
print("Get Swift help on forums.swift.org")
} else {
print("Unrecognized number")
}
}
}
let dial = TelephoneExchange()
// 使用动态方法调用
dial(4, 1, 1)
// 打印“Get Swift help on forums.swift.org”
dial(8, 6, 7, 5, 3, 0, 9)
// 打印“Unrecognized number”
// 直接调用底层方法
dial.dynamicallyCall(withArguments: [4, 1, 1])
```
`dynamicallyCall(withArguments:)` 方法的声明必须至少有一个参数遵循 [`ExpressibleByArrayLiteral`](https://developer.apple.com/documentation/swift/expressiblebyarrayliteral) 协议,如 `[Int]`,而返回值类型可以是任意类型。
```swift
@dynamicCallable
struct Repeater {
func dynamicallyCall(withKeywordArguments pairs: KeyValuePairs<String, Int>) -> String {
return pairs
.map { label, count in
repeatElement(label, count: count).joined(separator: " ")
}
.joined(separator: "\n")
}
}
let repeatLabels = Repeater()
print(repeatLabels(a: 1, b: 2, c: 3, b: 2, a: 1))
// a
// b b
// c c c
// b b
// a
```
`dynamicallyCall(withKeywordArguments:)` 方法声明必须至少有一个参数遵循 [`ExpressibleByDictionaryLiteral`](https://developer.apple.com/documentation/swift/expressiblebydictionaryliteral) 协议,返回值可以任意类型。参数的 [`Key`](https://developer.apple.com/documentation/swift/expressiblebydictionaryliteral/2294108-key) 必须遵循 [`ExpressibleByStringLiteral`](https://developer.apple.com/documentation/swift/expressiblebystringliteral) 协议。上述的示例使用 [`KeyValuePairs`](https://developer.apple.com/documentation/swift/keyvaluepairs) 作为参数类型,以便调用者可以传入重复的参数标签,`a``b` 在调用 `repeat`中多次使用。
如果你同时实现两种 `dynamicallyCall` 方法,则当在方法调用中包含关键字参数时,会调用 `dynamicallyCall(withKeywordArguments:)` 方法,否则调用 `dynamicallyCall(withArguments:)` 方法。
你只能调用参数和返回值与 `dynamicallyCall` 方法实现匹配的动态调用实例。在下面示例的调用无法编译,因为其 `dynamicallyCall(withArguments:)` 实现不接受 `KeyValuePairs<String, String>` 参数。
```swift
repeatLabels(a: "four") // Error
```
### `dynamicMemberLookup` {#dynamicmemberlookup}
该特性用于类、结构体、枚举或协议,让其能在运行时查找成员。该类型必须实现 `subscript(dynamicMemberLookup:)` 下标。
在显式成员表达式中,如果没有成名指定成员,则该表达式被理解为对该类型的 `subscript(dynamicMemberLookup:)` 下标的调用,传递包含成员名称字符串的参数。下标接收参数既可以是键路径,也可以是成员名称字符串;如果你同时实现这两种方式的下标调用,那么以键路径参数方式为准。
`subscript(dynamicMemberLookup:)` 实现允许接收 [`KeyPath`](https://developer.apple.com/documentation/swift/keypath)[`WritableKeyPath`](https://developer.apple.com/documentation/swift/writablekeypath) 或 [`ReferenceWritableKeyPath`](https://developer.apple.com/documentation/swift/referencewritablekeypath) 类型的键路径参数。而遵循 [`ExpressibleByStringLiteral`](https://developer.apple.com/documentation/swift/expressiblebystringliteral) 协议,下标调用接收参数为成员名称字符串 —— 在大多数情况下,下标的参数是一个 `String` 值。下标返回值类型可以为任意类型。
根据成员名称来动态地查找成员,可以帮助我们创建一个包裹数据的包装类型,但该类型无法在编译时进行类型检查,例如其他语言的数据桥接到 Swift 语言时。例如:
```swift
@dynamicMemberLookup
struct DynamicStruct {
let dictionary = ["someDynamicMember": 325,
"someOtherMember": 787]
subscript(dynamicMember member: String) -> Int {
return dictionary[member] ?? 1054
}
}
let s = DynamicStruct()
// 使用动态成员查找
let dynamic = s.someDynamicMember
print(dynamic)
// 打印“325”
// 直接调用底层下标
let equivalent = s[dynamicMember: "someDynamicMember"]
print(dynamic == equivalent)
// 打印“true”
```
根据键路径来动态地查找成员,可用于创建一个包裹数据的包装类型,该类型在编译时期进行类型检查。例如:
```swift
struct Point { var x, y: Int }
@dynamicMemberLookup
struct PassthroughWrapper<Value> {
var value: Value
subscript<T>(dynamicMember member: KeyPath<Value, T>) -> T {
get { return value[keyPath: member] }
}
}
let point = Point(x: 381, y: 431)
let wrapper = PassthroughWrapper(value: point)
print(wrapper.x)
```
### `GKInspectable` {#gkinspectable}
应用此属性,暴露一个自定义 GameplayKit 组件属性给 SpriteKit 编辑器 UI。
### `inlinable` {#inlinable}
该特性用于函数、方法、计算属性、下标、便利构造器或析构器的声明,以将该声明的实现公开为模块公开接口的一部分。编译器允许在调用处把 `inlinable` 标记的符号替换为符号实现的副本。
内联代码可以与任意模块中 `public` 访问级别的符号进行交互,同时可以与在相同模块中标记 `usableFromInline` 特性的 `internal` 访问级别的符号进行交互。内联代码不能与 `private``fileprivate` 级别的符号进行交互。
该特性不能用于嵌套在函数内的声明,也不能用于 `fileprivate``private` 访问级别的声明。在内联函数定义的函数和闭包是隐式非内联的,即使他们不能标记该特性。
### `nonobjc` {#nonobjc}
该特性用于方法、属性、下标、或构造器的声明,这些声明本可以在 Objective-C 代码中使用,而使用 `nonobjc` 特性则告诉编译器这个声明不能在 Objective-C 代码中使用。
该特性用在扩展中,与在没有明确标记为 `objc` 特性的扩展中给每个成员添加该特性具有相同效果。
可以使用 `nonobjc` 特性解决标有 `objc` 的类中桥接方法的循环问题,该特性还允许对标有 `objc` 的类中的构造器和方法进行重载。
标有 `nonobjc` 特性的方法不能重写标有 `objc` 特性的方法。然而,标有 `objc` 特性的方法可以重写标有 `nonobjc` 特性的方法。同样,标有 `nonobjc` 特性的方法不能满足标有 `@objc` 特性的协议中的方法要求。
### `NSApplicationMain` {#nsapplicationmain}
在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `NSApplicationMain(_:_:)` 函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
如果你不想使用这个特性,可以提供一个 `main.swift` 文件,并在代码**顶层**调用 `NSApplicationMain(_:_:)` 函数,如下所示:
```swift
import AppKit
NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
```
### `NSCopying` {#nscopying}
该特性用于修饰一个类的存储型变量属性。该特性将使属性的设值方法使用传入值的副本进行赋值,这个值由传入值的 `copyWithZone(_:)` 方法返回。该属性的类型必需符合 `NSCopying` 协议。
`NSCopying` 特性的行为与 Objective-C 中的 `copy` 特性相似。
### `NSManaged` {#nsmanaged}
该特性用于修饰 `NSManagedObject` 子类中的实例方法或存储型变量属性,表明它们的实现由 `Core Data` 在运行时基于相关实体描述动态提供。对于标记了 `NSManaged` 特性的属性,`Core Data` 也会在运行时为其提供存储。应用这个特性也意味着 `objc` 特性。
### `objc` {#objc}
该特性用于修饰任何可以在 Objective-C 中表示的声明。比如,非嵌套类、协议、非泛型枚举(仅限原始值为整型的枚举)、类和协议中的属性和方法(包括存取方法)、构造器、析构器以及下标运算符。`objc` 特性告诉编译器这个声明可以在 Objective-C 代码中使用。
该特性用在扩展中,与在没有明确标记为 `nonobjc` 特性的扩展中给每个成员添加该特性具有相同效果。
编译器隐式地将 `objc` 特性添加到 Objective-C 中定义的任何类的子类。但是,子类不能是泛型的,并且不能继承于任何泛型类。你可以将 `objc` 特性显式添加到满足这些条件的子类,来指定其 Objective-C 名称,如下所述。添加了 `objc` 的协议不能继承于没有此特性的协议。
在以下情况中隐式添加了 `objc` 特性。
- 父类有 `objc` 特性,且重写为子类的声明。
- 遵循带有 `objc` 特性协议的声明。
- 带有 `IBAction``IBSegueAction``IBOutlet``IBDesignable``IBInspectable``NSManaged``GKInspectable` 特性的声明。
如果你将 `objc` 特性应用于枚举,每一个枚举用例都会以枚举名称和用例名称组合的方式暴露在 Objective-C 代码中。例如,在 `Planet` 枚举中有一个名为 `Venus` 的用例,该用例暴露在 Objective-C 代码中时叫做 `PlanetVenus`
`objc` 特性有一个可选的参数,由标识符构成。当你想把 `objc` 所修饰的实体以一个不同的名字暴露给 Objective-C 时,你就可以使用这个特性参数。你可以使用这个参数来命名类、枚举类型、枚举用例、协议、方法、存取方法以及构造器。如果你要指定类、协议或枚举在 Objective-C 下的名称,在名称上包含三个字母的前缀,如 [Objective-C 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011210) 中的 [约定](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Conventions/Conventions.html#//apple_ref/doc/uid/TP40011210-CH10-SW1)。下面的例子把 `ExampleClass` 中的 `enabled` 属性的取值方法暴露给 Objective-C名字是 `isEnabled`,而不是它原来的属性名。
```swift
class ExampleClass: NSObject {
@objc var enabled: Bool {
@objc(isEnabled) get {
// 返回适当的值
}
}
}
```
### `objcMembers` {#objcmembers}
该特性用于类声明,以将 `objc` 特性应用于该类、扩展、子类以及子类的扩展的所有 Objective-C 兼容成员。
大多数代码应该使用 `objc` 特性,以暴露所需的声明。如果需要暴露多个声明,可以将其分组到添加 `objc` 特性的扩展中。`objcMembers` 特性为大量使用 Objective-C 运行时的内省工具的库提供了便利。添加不必要的 `objc` 特性会增加二进制体积并影响性能。
### `requires_stored_property_inits` {#requires-stored-property-inits}
该特性用于类声明,以要求类中所有存储属性提供默认值作为其定义的一部分。对于从中继承的任何类都推断出 `NSManagedObject` 特性。
### `testable` {#testable}
在导入允许测试的编译模块时,该特性用于修饰 `import` 声明,这样就能访问被导入模块中的任何标有 `internal` 访问级别修饰符的实体,犹如它们被标记了 `public` 访问级别修饰符。测试也可以访问使用 `internal` 或者 `public` 访问级别修饰符标记的类和类成员,就像它们是 `open` 访问修饰符声明的。
### `UIApplicationMain` {#uiapplicationmain}
在类上使用该特性表示该类是应用程序委托类,使用该特性与调用 `UIApplicationMain` 函数并且把该类的名字作为委托类的名字传递给函数的效果相同。
如果你不想使用这个特性,可以提供一个 `main.swift` 文件,并在代码顶层调用 `UIApplicationMain(_:_:_:_:)` 函数。比如,如果你的应用程序使用一个继承于 UIApplication 的自定义子类作为主要类,你可以调用 `UIApplicationMain(_:_:_:_:)` 函数而不是使用该特性。
### `usableFromInline` {#usablefrominline}
该特性用于函数、方法、计算属性、下标、构造器或析构器的声明,以在同一模块中允许该符号用于内联代码的声明。声明必须具有 `internal` 访问级别修饰符。
`public` 访问修饰符相同的是,该特性将声明公开为模块公共接口的一部分。区别于 `public`,编译器不允许在模块外部的代码通过名称引用 `usableFromInline` 标记的声明,即使导出了声明符号也是无法引用。但是,模块外的代码仍然可以通过运行时交换声明符号。
标记为 `inlinable` 特性的声明,在内联代码中可以隐式使用。虽然 `inlinable``usableFromInline` 可以用于 `internal` 声明,但这两者不能同时使用。
### `warn_unqualified_access` {#warn-unqualified-access}
该特性应用于顶级函数、实例方法、类方法或静态方法,以在没有前置限定符(例如模块名称、类型名称、实例变量或常量)的情况下使用该函数或方法时触发警告。使用该特性可以帮助减少在同一作用于访问同名函数之间的歧义。
例如Swift 标准库包含 [`min(_:_:)`](https://developer.apple.com/documentation/swift/1538339-min/) 顶级函数和用于序列比较元素的 [`min()`](https://developer.apple.com/documentation/swift/sequence/1641174-min) 方法。序列方法声明使用了 `warn_unqualified_access`,以减少在 `Sequence` 扩展中使用它们的歧义。
### Interface Builder 使用的声明特性 {#declaration-attributes-used-by-interface-builder}
`Interface Builder` 特性是 `Interface Builder` 用来与 Xcode 同步的声明特性。`Swift` 提供了以下的 `Interface Builder` 特性:`IBAction``IBSegueAction``IBOutlet``IBDesignable`,以及 `IBInspectable` 。这些特性与 Objective-C 中对应的特性在概念上是相同的。
`IBOutlet``IBInspectable` 用于修饰一个类的属性声明,`IBAction` 特性用于修饰一个类的方法声明,`IBDesignable` 用于修饰类的声明。
应用 `IBAction``IBSegueAction``IBOutlet``IBDesignable` 或者 `IBInspectable` 特性都意味着同时应用 `objc` 特性。
## 类型特性 {#type-attributes}
类型特性只能用于修饰类型。
### `autoclosure` {#autoclosure}
这个特性通过把表达式自动封装成无参数的闭包来延迟表达式的计算。它可以修饰类型为返回表达式结果类型的无参数函数类型的函数参数。关于如何使用 autoclosure 特性的例子,请参阅 [自动闭包](../chapter2/07_Closures.md#autoclosures) 和 [函数类型](./03_Types.md#function_type)。
### `convention` {#convention}
该特性用于修饰函数类型,它指出了函数调用的约定。
convention 特性总是与下面的参数之一一起出现。
- `swift` 参数用于表示一个 Swift 函数引用。这是 Swift 中函数值的标准调用约定。
- `block` 参数用于表示一个 Objective-C 兼容的块引用。函数值会作为一个块对象的引用,块是一种 `id` 兼容的 Objective-C 对象,其中嵌入了调用函数。调用函数使用 C 的调用约定。
- `c` 参数用于表示一个 C 函数引用。函数值没有上下文,不具备捕获功能,同样使用 C 的调用约定。
使用 C 函数调用约定的函数也可用作使用 Objective-C 块调用约定的函数,同时使用 Objective-C 块调用约定的函数也可用作使用 Swift 函数调用约定的函数。然而,只有非泛型的全局函数、局部函数以及未捕获任何局部变量的闭包,才可以被用作使用 C 函数调用约定的函数。
### `escaping` {#escaping}
在函数或者方法声明上使用该特性,它表示参数将不会被存储以供延迟执行,这将确保参数不会超出函数调用的生命周期。在使用 `escaping` 声明特性的函数类型中访问属性和方法时不需要显式地使用 `self.`。关于如何使用 `escaping` 特性的例子,请参阅 [逃逸闭包](../chapter2/07_Closures.md#escaping_closures)。
## Switch Case 特性 {#switch-case-attributes}
你只能在 switch cases 中使用 switch case 特性。
### `unknown` {#unknown}
次特性用于 switch case表示在编译时该地方不会匹配枚举的任何情况。有关如何使用 `unknown` 特性的示例,可参阅 [对未来枚举的 `case` 进行 `switch`](./05_Statements.md#future-case)。
> 特性语法
>
>
>
#### attribute {#attribute}
>
> *特性*→ [特性名](#attribute_name) [特性参数子句](#atribute_argument_clause)<sub>可选</sub>
>
>
#### attribute_name {#attribute-name}
>
> *特性名* → [标识符](./02_Lexical_Structure.md#identifier)
>
>
#### atribute_argument_clause {#atribute-argument-clause}
>
> *特性参数子句* → **(** [均衡令牌列表](#balanced_tokens)<sub>可选</sub> **)**
>
>
#### attributes {#attributes}
>
> *特性列表* → [特性](#attribute) [特性列表](#attributes)<sub>可选</sub>
>
>
>
#### balanced_tokens {#balanced-tokens}
>
> *均衡令牌列表* → [均衡令牌](#balanced_token) [均衡令牌列表](#balanced_tokens)<sub>可选</sub>
>
>
#### balanced_token {#balanced-token}
>
> *均衡令牌* → **(** [均衡令牌列表](#balanced_tokens)<sub>可选</sub> **)**
>
> *均衡令牌* → **\[** [均衡令牌列表](#balanced_tokens)<sub>可选</sub> **\]**
>
> *均衡令牌* → **{** [均衡令牌列表](#balanced_tokens)<sub>可选</sub> **}**
>
> *均衡令牌* → 任意标识符,关键字,字面量或运算符
>
> *均衡令牌* → 任意标点除了 **(****)****[****]****{**,或 **}**
>

View File

@ -14,10 +14,12 @@ Swift 官方文档中文翻译由 [numbbbbb](https://github.com/numbbbbb) 发起
- [Hale](https://github.com/wuqiuhao)
- [Joeytat](https://github.com/joeytat)
- [jojotov](https://github.com/jojotov)
- [Licardo](https://github.com/L1cardo)
- [Khala-wan](https://github.com/Khala-wan)
- [Nemocdz](https://github.com/Nemocdz)
- [numbbbbb](https://github.com/numbbbbb)
- [pmst](https://github.com/colourful987)
- [Phenmod](https://github.com/Phenmod)
- [RickeyBoy](https://github.com/RickeyBoy)
- [SunsetWan](https://github.com/SunsetWan)
- [WAMaker](https://github.com/WAMaker)

View File

@ -11,7 +11,7 @@
> 小明说哇靠学姐你还会妖法......
Swift 语言从 Xcode 6 beta 5版本起加入了对权限控制Access Control的支持。其实权限控制和小明的物品一样你可以设定水壶是只有自己能用还是只有宿舍里的人能用还是全校都可以用。
Swift 语言从 Xcode 6 beta 5 版本起加入了对权限控制Access Control的支持。其实权限控制和小明的物品一样你可以设定水壶是只有自己能用还是只有宿舍里的人能用还是全校都可以用。
从此以后,你可以好像神盾局局长一样,完全掌控自己的代码块的”保密级别“,哪些是只能在本文件引用,哪些能用在整个项目里,你还可以发挥大爱精神,把它开源成只要导入你的框架,大家都可以使用的 API。