88 Commits

Author SHA1 Message Date
a064d9f4d6 Update 25_Access_Control.md 2019-07-23 23:35:13 -05:00
b7a8566a0f 校对 (#973)
* Update 09_Structures_And_Classes.md

驼峰

* Update 17_Error_Handling.md

病句
2019-07-23 23:31:38 -05:00
ebda86cd05 Merge pull request #969 from xuezhulian/patch-1
Update 05_Control_Flow.md
2019-07-18 15:31:53 +08:00
546db6bc47 Update 05_Control_Flow.md
swith -> switch
2019-07-18 13:49:10 +08:00
3d64a8e5e6 trigger gitbook building 2019-07-15 06:35:00 -05:00
b95202eb6d Update 03_Strings_and_Characters.md (#967) 2019-07-15 06:30:00 -05:00
ed7eb9e045 Update 22_Generics.md 2019-07-15 05:24:12 -05:00
15ee26ca6d Update 04_revision_history.md 2019-07-15 05:23:45 -05:00
dca10b1aa0 修正翻译错误 (#965)
* 修正翻译错误

* Update 14_Initialization.md
2019-07-15 04:50:12 -05:00
2d10a8d6ec 修改翻译 (#964) 2019-07-14 20:57:21 -07:00
a6d6e468f6 Merge pull request #963 from Nemocdz/gh-pages
fix 一处格式问题
2019-07-12 11:38:40 +08:00
72708963ab fix typo 2019-07-12 11:37:23 +08:00
22265fa31d Merge remote-tracking branch 'upstream/gh-pages' into gh-pages 2019-07-12 11:36:26 +08:00
771c5b3da0 trigger gitbook update 2019-07-11 10:39:39 +08:00
0369884f87 Update contributors.md 2019-07-10 20:24:13 +08:00
75e0837fb0 Update contributors.md 2019-07-10 20:22:55 +08:00
0afcd2ebf1 Update README.md 2019-07-10 18:32:54 +08:00
d07fdbfb98 更新 Revision History (#962)
* 术语表更新

* 更新文档内术语

* 术语表更新

* update Control Flow

* update Version Compatibility

* update Methods

* update Types

* 术语表更新

* update Types

* Update 03_Types.md

* update links

* update Links

* 统一版本历史记录格式和翻译

* fix typo

* fix typo

* Update 04_revision_history.md

* update Document Revision History

* update Revision History&Types
2019-07-10 18:07:50 +08:00
21e80f09b5 update Revision History&Types 2019-07-10 17:01:13 +08:00
2b140081de Merge remote-tracking branch 'upstream/gh-pages' into gh-pages 2019-07-10 16:17:49 +08:00
60cc810915 Update SUMMARY.md 2019-07-10 15:59:55 +08:00
68e51d7f57 完成翻译:不透明类型 (#961)
* 新增翻译:不透明类型

* 优化格式
2019-07-10 15:57:13 +08:00
4381756f0f Merge pull request #960 from lal603743923/gh-pages
Update 03_a_swift_tour.md
2019-07-10 14:48:33 +08:00
96f3c84b8a Update 03_a_swift_tour.md
修正翻译错误.
2019-07-09 20:57:20 +08:00
cc029194be 04_Collection_Types (#959)
* 04_Collection_Types 5.1初版

* 校对以后的更新

* 第二次校对以后的修正
2019-07-07 11:08:11 +08:00
ae117bdfbc #939 & #949 (#958)
* Protocol -  protocol type downcasting

* Protocols - 统一用语

* Properties - Shorthand getter

* Properties - 标点及语气调整。

* Update 10_Properties.md
2019-07-03 20:36:45 -07:00
5fc4252bfc Update FUNDING.yml 2019-07-03 14:12:24 +08:00
9ec61ba488 Create FUNDING.yml 2019-07-03 14:09:16 +08:00
fc89e3ca5d Merge pull request #957 from SunsetWan/sunsetwan-translation
Complete the translation of issue  942 and 941
2019-07-01 16:52:49 +08:00
9a629a57e3 Merge branch 'sunsetwan-translation' of https://github.com/SunsetWan/the-swift-programming-language-in-chinese into sunsetwan-translation 2019-07-01 13:41:53 +08:00
787687cb1e Refine the translation. 2019-07-01 13:40:57 +08:00
b699654ab8 update Document Revision History 2019-07-01 00:23:20 +08:00
d902be8367 Merge branch 'gh-pages' into sunsetwan-translation 2019-07-01 00:09:07 +08:00
d90c50ec74 Refine the translation. 2019-07-01 00:06:35 +08:00
4894951c3b 22 Generics Swift 5.1 更新 (#956) 2019-06-30 07:25:08 -05:00
b5defb4c0e Complete the translation of issue 942 and 941. 2019-06-30 18:55:05 +08:00
b1887d01ac Merge remote-tracking branch 'upstream/gh-pages' into gh-pages 2019-06-30 00:10:02 +08:00
5f0da139f0 统一版本历史记录翻译及格式 (#955)
* 术语表更新

* 更新文档内术语

* 术语表更新

* update Control Flow

* update Version Compatibility

* update Methods

* update Types

* 术语表更新

* update Types

* Update 03_Types.md

* update links

* update Links

* 统一版本历史记录格式和翻译

* fix typo

* fix typo

* Update 04_revision_history.md
2019-06-29 11:00:30 -05:00
53eaaeb19c Update 04_revision_history.md 2019-06-29 11:00:19 -05:00
c9c9bb980e fix typo 2019-06-29 23:45:34 +08:00
51ceab425c Merge remote-tracking branch 'upstream/gh-pages' into gh-pages
# Conflicts:
#	source/chapter1/04_revision_history.md
2019-06-29 23:39:14 +08:00
16cae8adf6 fix typo 2019-06-29 23:34:09 +08:00
bab43e7db6 统一版本历史记录格式和翻译 2019-06-29 23:33:23 +08:00
4cace74528 Complete the translation of issue 937 and 935. (#954) 2019-06-29 08:28:58 -05:00
b807a6edb9 Complete the translation of issue 937 and 935. 2019-06-29 19:34:54 +08:00
1a6d56d228 统一链接格式 (#953)
* 术语表更新

* 更新文档内术语

* 术语表更新

* update Control Flow

* update Version Compatibility

* update Methods

* update Types

* 术语表更新

* update Types

* Update 03_Types.md

* update links

* update Links
2019-06-27 17:35:37 -05:00
004fc0906d Merge remote-tracking branch 'upstream/gh-pages' into gh-pages
# Conflicts:
#	source/chapter2/11_Methods.md
#	source/chapter3/03_Types.md
2019-06-28 00:59:06 +08:00
850cf97f83 Merge branch 'gh-pages' of github.com:Nemocdz/the-swift-programming-language-in-chinese into gh-pages 2019-06-28 00:54:45 +08:00
d6862fa4dc update Links 2019-06-28 00:54:02 +08:00
d3efb989d3 update links 2019-06-28 00:09:46 +08:00
0f2ab87dca Delete config.json 2019-06-26 11:16:25 -05:00
9a6f016f45 Delete change_cdn.py 2019-06-26 11:16:11 -05:00
2164db3b8b Update index.html 2019-06-26 11:16:01 -05:00
fb2dfa6764 Delete googleb0a4f5a22e9cb82f.html 2019-06-26 11:15:16 -05:00
d8068f4325 Delete CNAME 2019-06-26 11:14:35 -05:00
4e4e291956 更新文档翻译 (#952)
* 术语表更新

* 更新文档内术语

* 术语表更新

* update Control Flow

* update Version Compatibility

* update Methods

* update Types

* 术语表更新

* update Types

* Update 03_Types.md
2019-06-26 11:05:31 -05:00
2f430495d4 Update 03_Types.md 2019-06-26 11:05:20 -05:00
7b123505db Merge remote-tracking branch 'upstream/gh-pages' into gh-pages
# Conflicts:
#	README.md
#	source/chapter3/06_Declarations.md
2019-06-26 23:55:25 +08:00
e7def896cb update Types 2019-06-26 23:42:11 +08:00
5fbfc38fd7 remove extra > 2019-06-26 10:02:48 -05:00
b26f8aacff 术语表更新 2019-06-26 22:42:22 +08:00
b76f8cf111 Translate Chapter3 06_Declarations and 07_Attributes (#951)
* 完成 Chapter3 Declarations Swift5.1 Update

* Update 07_Attributes.md
2019-06-26 09:37:39 -05:00
ca87420665 update Types 2019-06-26 21:20:01 +08:00
93c390dd5a update Methods 2019-06-26 19:44:58 +08:00
7020682acd update Version Compatibility 2019-06-26 19:31:54 +08:00
aa91ad4692 update Control Flow 2019-06-26 19:16:32 +08:00
367cece0f5 术语更新 (#950)
* 术语表更新

* 更新文档内术语

* 术语表更新
2019-06-25 10:00:42 -05:00
3f0cc6c047 术语表更新 2019-06-25 22:49:28 +08:00
65dc6b133f 更新文档内术语 2019-06-25 22:43:20 +08:00
b58d744852 术语表更新 2019-06-25 22:40:17 +08:00
e9aaa026c6 Merge pull request #949 from Nemocdz/gh-pages
remove unused files
2019-06-23 23:03:11 +08:00
1167a215c9 remove unused files 2019-06-23 23:00:55 +08:00
f5c9d9c5e5 Update README.md 2019-06-23 09:30:05 -05:00
71f0757ba0 Merge pull request #931 from Nemocdz/gh-pages
更新 Swift 5.1 文档(beta)
2019-06-23 11:25:24 +08:00
afc8cddb0e update document 2019-06-23 11:17:57 +08:00
a3a7770b9a Merge remote-tracking branch 'upstream/gh-pages' into gh-pages
# Conflicts:
#	source/chapter2/09_Structures_And_Classes.md
2019-06-23 10:59:04 +08:00
1ffeeeedaf Update 14_Initialization.md 2019-06-16 07:43:03 -05:00
b991a4eb75 Update 04_Expressions.md (#929)
有几处的binary被错误翻译成了二进制,本意应为二元
2019-05-19 11:28:54 +08:00
e3c9bd7992 Update 02_version_compatibility.md (#926) 2019-05-03 18:57:44 -05:00
425d534e7f Update 25_Access_Control.md (#925) 2019-04-21 11:44:58 -05:00
e0af10bc8e Update 21_Protocols.md (#924) 2019-04-20 21:43:29 -05:00
3210e30972 Revert "test gitbook anchor"
This reverts commit e82cea3866.
2019-04-19 12:28:19 -05:00
e82cea3866 test gitbook anchor 2019-04-19 12:23:34 -05:00
497d68be37 fix invalid url (#923) 2019-04-15 08:37:38 -05:00
cb2ebd282b Update 01_The_Basics.md 2019-04-12 07:24:30 -05:00
9fd540b8d7 校对: chapter2/03_Strings_and_Characters 方法名变化 (#921)
index(of:) 已更名为: firstIndex(of:)
2019-04-11 21:32:20 -05:00
86690d4472 Update contributors.md 2019-04-11 19:26:46 -05:00
de559ce2d8 update swift 5.0 2019-02-04 01:25:04 +08:00
48 changed files with 8746 additions and 8373 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [SketchK, numbbbbb]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

1
CNAME
View File

@ -1 +0,0 @@
gg.swiftguide.cn

View File

@ -5,19 +5,19 @@
[英文原版在线版](https://docs.swift.org/swift-book/) [英文原版在线版](https://docs.swift.org/swift-book/)
[英文原版ePub版](https://docs.swift.org/swift-book/TheSwiftProgrammingLanguageSwift5.epub)
# 在线阅读 # 在线阅读
使用 GitBook 制作,可以直接 [在线阅读](https://swiftgg.gitbook.io/swift/)。 使用 GitBook 制作,可以直接 [在线阅读](https://swiftgg.gitbook.io/swift/)。
# 当前阶段 # 当前阶段
- 更新到 Swift 5.12019-07-10
- 更新到 Swift 5.02019-04-05 - 更新到 Swift 5.02019-04-05
- 更新到 Swift 4.22019-01-29 - 更新到 Swift 4.22019-01-29
- 更新到 Swift 4.12018-04-12感谢 [@Mylittleswift](https://github.com/Mylittleswift) - 更新到 Swift 4.12018-04-12感谢 [@Mylittleswift](https://github.com/Mylittleswift)
- 更新到 Swift 3.02016-09-23 - 更新到 Swift 3.02016-09-23
# 贡献力量 # 贡献力量
如果想做出贡献的话,你可以: 如果想做出贡献的话,你可以:
@ -59,22 +59,22 @@ diff 操作如下:
| --- | --- | | --- | --- |
| argument | 实参 | | argument | 实参 |
| parameter | 形参 | | parameter | 形参 |
| associatedtype | 关联类型 | | associated type | 关联类型 |
| range | 区间 | | range | 区间 |
| type property | 类型属性 | | type property | 类型属性 |
| Unary operator | 一元运算符 | | unary operator | 一元运算符 |
| Binary operator | 二元运算符 | | binary operator | 二元运算符 |
| Ternary operator | 三元运算符 | | ternary operator | 三元运算符 |
| Labeled Statement | 具名语句 | | labeled statement | 具名语句 |
| conform Protocol | 遵循协议 | | conform protocol | 遵循协议 |
| availability-condition | 可用性条件 | | availability-condition | 可用性条件 |
| fallthrough | 贯穿 | | fallthrough | 贯穿 |
| Branch Statement | 分支语句 | | branch statement | 分支语句 |
| Control Transfer Statement | 控制传递语句 | | control transfer statement | 控制传递语句 |
| Type Annotation | 类型注 | | type annotation | 类型注 |
| Type Identifier | 类型标识符 | | type identifier | 类型标识符 |
| Metatype Type | 元类型 | | metatype type | 元类型 |
| Protocol Composition Type | 复合协议类型 | | protocol composition type | 复合协议类型 |
| associated value | 关联值 | | associated value | 关联值 |
| raw value | 原始值 | | raw value | 原始值 |
| computed property | 计算属性 | | computed property | 计算属性 |
@ -87,21 +87,21 @@ diff 操作如下:
| statement | 语句 | | statement | 语句 |
| expression | 表达式 | | expression | 表达式 |
| optional | 可选 | | optional | 可选 |
| Implicitly Unwrapped optional | 隐式解包可选值 | | implicitly unwrapped optional | 隐式解包可选值 |
| Optional Binding | 可选绑定 | | optional binding | 可选绑定 |
| optional chaining | 可选链 | | optional chaining | 可选链 |
| collection | 集合 | | collection | 集合 |
| convention | 约定 | | convention | 约定 |
| iterate | 迭代 | | iterate | 迭代 |
| nest | 嵌套 | | nest | 嵌套 |
| Inheritance | 继承 | | inheritance | 继承 |
| override | 重写 | | override | 重写 |
| base class | 基类 | | base class | 基类 |
| Designated Initializer | 指定构造器 | | designated initializer | 指定构造器 |
| Convenience Initializer | 便利构造器 | | convenience initializer | 便利构造器 |
| Automatic Reference Counting | 自动引用计数 | | automatic reference counting | 自动引用计数 |
| type inference | 类型推断 | | type inference | 类型推断 |
| Type Casting | 类型转换 | | type casting | 类型转换 |
| unwrapped | 解包 | | unwrapped | 解包 |
| wrapped | 包装 | | wrapped | 包装 |
| note | 注意 | | note | 注意 |
@ -109,7 +109,7 @@ diff 操作如下:
| tuple | 元组 | | tuple | 元组 |
| first-class | 一等 | | first-class | 一等 |
| deinitializer | 析构器 | | deinitializer | 析构器 |
| Initializer | 构造器 | | initializer | 构造器 |
| initialization | 构造过程 | | initialization | 构造过程 |
| deinitialization | 析构过程 | | deinitialization | 析构过程 |
| getter | 不翻译 | | getter | 不翻译 |
@ -118,15 +118,18 @@ diff 操作如下:
| property | 属性 | | property | 属性 |
| attribute | 特性或者属性,根据上下文 | | attribute | 特性或者属性,根据上下文 |
| method | 方法 | | method | 方法 |
| Enumeration | 枚举 | | enumeration | 枚举 |
| Structure | 结构体 | | structure | 结构体 |
| Protocol | 协议 | | protocol | 协议 |
| Extension | 扩展 | | extension | 扩展 |
| Generic | 泛型 | | generic | 泛型 |
| literal value | 字面量 | | literal value | 字面量 |
| alias | 别名 | | alias | 别名 |
| Assertion | 断言 | | assertion | 断言 |
| conditional compilation | 条件编译 | | conditional compilation | 条件编译 |
| opaque type | 不透明类型 |
| function | 函数 |
| runtime | 运行时 |
# 贡献者 # 贡献者

View File

@ -1,22 +0,0 @@
#!/usr/bin/python
# coding:utf-8
import os
def iter(path):
for root, dirs, files in os.walk(path):
for fn in files:
if fn.endswith(".html"):
with open(root + '/' + fn, 'r') as f:
content = f.read()
content = content.replace('<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/ace.js"></script>', '<script src="http://cdn.bootcss.com/ace/1.1.3/ace.js"></script>').replace('<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/mode-javascript.js"></script>', '<script src="http://cdn.bootcss.com/ace/1.1.3/mode-javascript.js"></script>')
insert_pos = content.find("</li>", content.find("Generated using GitBook")) + 6
content = content[:insert_pos] + '''<li style="margin-left:15%;"> <iframe src="http://ghbtns.com/github-btn.html?user=numbbbbb&repo=the-swift-programming-language-in-chinese&type=watch&count=true&size=large"
allowtransparency="true" frameborder="0" scrolling="0" width="170" height="30"></iframe></li>''' + content[insert_pos:]
content.replace(r'<title>.*?</title>', "<title>《The Swift Programming Language》完整中文版</title>")
with open(root + '/' + fn, 'w') as f:
f.write(content)
iter(os.getcwd())

View File

@ -1,9 +0,0 @@
{
"name": "The Swift Programming Language 中文版",
"introduction": "中文版《The Swift Programming Language》",
"path": {
"content": "source",
"toc": "source/SUMMARY.md",
"readme": "source/README.md"
}
}

Binary file not shown.

View File

@ -1 +0,0 @@
google-site-verification: googleb0a4f5a22e9cb82f.html

View File

@ -1,19 +1,8 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html lang="en-US" manifest="./manifest.appcache"> <html lang="en-US" manifest="./manifest.appcache">
<head> <head>
<meta http-equiv="refresh" content="0; url=https://swiftgg.gitbook.io/swift/" />
<meta http-equiv="refresh" content="0; url=http://wiki.jikexueyuan.com/project/swift/" />
</head> </head>
<body> <body>
<script type="text/javascript">
var _bdhmProtocol = (("https:" == document.location.protocol) ? " https://" : " http://");
document.write(unescape("%3Cscript src='" + _bdhmProtocol + "hm.baidu.com/h.js%3F21e159ce3496d7b5f80aa3c4f1370b04' type='text/javascript'%3E%3C/script%3E"));
</script>
</body> </body>
</html> </html>

View File

@ -28,6 +28,7 @@
* [扩展](chapter2/20_Extensions.md) * [扩展](chapter2/20_Extensions.md)
* [协议](chapter2/21_Protocols.md) * [协议](chapter2/21_Protocols.md)
* [泛型](chapter2/22_Generics.md) * [泛型](chapter2/22_Generics.md)
* [不透明类型](chapter2/27_Opaque_Types.md)
* [自动引用计数](chapter2/23_Automatic_Reference_Counting.md) * [自动引用计数](chapter2/23_Automatic_Reference_Counting.md)
* [内存安全](chapter2/24_Memory_Safety.md) * [内存安全](chapter2/24_Memory_Safety.md)
* [访问控制](chapter2/25_Access_Control.md) * [访问控制](chapter2/25_Access_Control.md)

View File

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

View File

@ -65,7 +65,7 @@ let fruitSummary = "I have \(apples + oranges) pieces of fruit."
> >
> 使用 `\()` 来把一个浮点计算转换成字符串,并加上某人的名字,和他打个招呼。 > 使用 `\()` 来把一个浮点计算转换成字符串,并加上某人的名字,和他打个招呼。
使用一对三个引号(`"""`)来包含多行字符串内容,字符串中的内容(包括引号、空格、换行符等)都会保留下来。举个例子: 使用三个引号(`"""`)来包含多行字符串内容,字符串中的内容(包括引号、空格、换行符等)都会保留下来。举个例子:
```swift ```swift
let quotation = """ let quotation = """

View File

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

View File

@ -2,7 +2,7 @@
Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 应用的新语言。然而,如果你有 C 或者 Objective-C 开发经验的话,你会发现 Swift 的很多内容都是你熟悉的。 Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 应用的新语言。然而,如果你有 C 或者 Objective-C 开发经验的话,你会发现 Swift 的很多内容都是你熟悉的。
Swift 包含了 C 和 Objective-C 上所有基础数据类型,`Int` 表示整型值; `Double``Float` 表示浮点型值; `Bool` 是布尔型值;`String` 是文本型数据。 Swift 还提供了三个基本的集合类型,`Array``Set``Dictionary` ,详见[集合类型](./04_Collection_Types.md)。 Swift 包含了 C 和 Objective-C 上所有基础数据类型,`Int` 表示整型值; `Double``Float` 表示浮点型值; `Bool` 是布尔型值;`String` 是文本型数据。 Swift 还提供了三个基本的集合类型,`Array``Set``Dictionary` ,详见 [集合类型](./04_Collection_Types.md)。
就像 C 语言一样Swift 使用变量来进行存储并通过变量名来关联值。在 Swift 中,广泛的使用着值不可变的变量,它们就是常量,而且比 C 语言的常量更强大。在 Swift 中,如果你要处理的值不需要改变,那使用常量可以让你的代码更加安全并且更清晰地表达你的意图。 就像 C 语言一样Swift 使用变量来进行存储并通过变量名来关联值。在 Swift 中,广泛的使用着值不可变的变量,它们就是常量,而且比 C 语言的常量更强大。在 Swift 中,如果你要处理的值不需要改变,那使用常量可以让你的代码更加安全并且更清晰地表达你的意图。
@ -41,11 +41,11 @@ var x = 0.0, y = 0.0, z = 0.0
> >
> 如果你的代码中有不需要改变的值,请使用 `let` 关键字将它声明为常量。只将需要改变的值声明为变量。 > 如果你的代码中有不需要改变的值,请使用 `let` 关键字将它声明为常量。只将需要改变的值声明为变量。
### 类型注 {#type-annotations} ### 类型注 {#type-annotations}
当你声明常量或者变量的时候可以加上*类型type annotation*,说明常量或者变量中要存储的值的类型。如果要添加类型注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称。 当你声明常量或者变量的时候可以加上*类型注type annotation*,说明常量或者变量中要存储的值的类型。如果要添加类型注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称。
这个例子给 `welcomeMessage` 变量添加了类型注,表示这个变量可以存储 `String` 类型的值: 这个例子给 `welcomeMessage` 变量添加了类型注,表示这个变量可以存储 `String` 类型的值:
```swift ```swift
var welcomeMessage: String var welcomeMessage: String
@ -63,7 +63,7 @@ var welcomeMessage: String
welcomeMessage = "Hello" welcomeMessage = "Hello"
``` ```
你可以在一行中定义多个同样类型的变量,用逗号分割,并在最后一个变量名之后添加类型注: 你可以在一行中定义多个同样类型的变量,用逗号分割,并在最后一个变量名之后添加类型注
```swift ```swift
var red, green, blue: Double var red, green, blue: Double
@ -71,7 +71,7 @@ var red, green, blue: Double
> 注意 > 注意
> >
> 一般来说你很少需要写类型注。如果你在声明常量或者变量的时候赋了一个初始值Swift 可以推断出这个常量或者变量的类型,请参考[类型安全和类型推断](#type_safety_and_type_inference)。在上面的例子中,没有给 `welcomeMessage` 赋初始值,所以变量 `welcomeMessage` 的类型是通过一个类型注指定的,而不是通过初始值推断的。 > 一般来说你很少需要写类型注。如果你在声明常量或者变量的时候赋了一个初始值Swift 可以推断出这个常量或者变量的类型,请参考 [类型安全和类型推断](#type-safety-and-type-inference)。在上面的例子中,没有给 `welcomeMessage` 赋初始值,所以变量 `welcomeMessage` 的类型是通过一个类型注指定的,而不是通过初始值推断的。
### 常量和变量的命名 {#naming} ### 常量和变量的命名 {#naming}
@ -116,7 +116,7 @@ print(friendlyWelcome)
// 输出“Bonjour!” // 输出“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 会用当前常量或变量的值替换这些占位符。将常量或变量名放入圆括号中,并在开括号前使用反斜杠将其转义: 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} ## 注释 {#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} ## 浮点数 {#floating-point-numbers}
@ -327,7 +327,7 @@ let twoThousandAndOne = twoThousand + UInt16(one)
现在两个数字的类型都是 `UInt16`,可以进行相加。目标常量 `twoThousandAndOne` 的类型被推断为 `UInt16`,因为它是两个 `UInt16` 值的和。 现在两个数字的类型都是 `UInt16`,可以进行相加。目标常量 `twoThousandAndOne` 的类型被推断为 `UInt16`,因为它是两个 `UInt16` 值的和。
`SomeType(ofInitialValue)` 是调用 Swift 构造器并传入一个初始值的默认方法。在语言内部,`UInt16` 有一个构造器,可以接受一个 `UInt8` 类型的值,所以这个构造器可以用现有的 `UInt8` 来创建一个新的 `UInt16`。注意,你并不能传入任意类型的值,只能传入 `UInt16` 内部有对应构造器的值。不过你可以扩展现有的类型来让它可以接收其他类型的值(包括自定义类型),请参考[扩展](./20_Extensions.md)。 `SomeType(ofInitialValue)` 是调用 Swift 构造器并传入一个初始值的默认方法。在语言内部,`UInt16` 有一个构造器,可以接受一个 `UInt8` 类型的值,所以这个构造器可以用现有的 `UInt8` 来创建一个新的 `UInt16`。注意,你并不能传入任意类型的值,只能传入 `UInt16` 内部有对应构造器的值。不过你可以扩展现有的类型来让它可以接收其他类型的值(包括自定义类型),请参考 [扩展](./20_Extensions.md)。
### 整数和浮点数转换 {#integer-and-floating-point-conversion} ### 整数和浮点数转换 {#integer-and-floating-point-conversion}
@ -396,7 +396,7 @@ if turnipsAreDelicious {
// 输出“Eww, turnips are horrible.” // 输出“Eww, turnips are horrible.”
``` ```
条件语句,例如 `if`,请参考[控制流](./05_Control_Flow.md)。 条件语句,例如 `if`,请参考 [控制流](./05_Control_Flow.md)。
如果你在需要使用 `Bool` 类型的地方使用了非布尔值Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误: 如果你在需要使用 `Bool` 类型的地方使用了非布尔值Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误:
@ -416,7 +416,7 @@ if i == 1 {
} }
``` ```
`i == 1` 的比较结果是 `Bool` 类型,所以第二个例子可以通过类型检查。类似 `i == 1` 这样的比较,请参考[基本操作符](./05_Control_Flow.md)。 `i == 1` 的比较结果是 `Bool` 类型,所以第二个例子可以通过类型检查。类似 `i == 1` 这样的比较,请参考 [基本操作符](./05_Control_Flow.md)。
和 Swift 中的其他类型安全的例子一样,这个方法可以避免错误并保证这块代码的意图总是清晰的。 和 Swift 中的其他类型安全的例子一样,这个方法可以避免错误并保证这块代码的意图总是清晰的。
@ -477,11 +477,11 @@ print("The status message is \(http200Status.description)")
// 输出“The status message is OK” // 输出“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_Classes_and_Structures.md)。
## 可选类型 {#optionals} ## 可选类型 {#optionals}
@ -552,7 +552,7 @@ if convertedNumber != nil {
// 输出“convertedNumber has an integer value of 123.” // 输出“convertedNumber has an integer value of 123.”
``` ```
更多关于 `if` 语句的内容,请参考[控制流](./05_Control_Flow.md)。 更多关于 `if` 语句的内容,请参考 [控制流](./05_Control_Flow.md)。
> 注意 > 注意
> >
@ -560,7 +560,7 @@ if convertedNumber != nil {
### 可选绑定 {#optional-binding} ### 可选绑定 {#optional-binding}
使用*可选绑定optional binding*来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在 `if``while` 语句中,这条语句不仅可以用来判断可选类型中是否有值,同时可以将可选类型中的值赋给一个常量或者变量。`if``while` 语句,请参考[控制流](./05_Control_Flow.md)。 使用*可选绑定optional binding*来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在 `if``while` 语句中,这条语句不仅可以用来判断可选类型中是否有值,同时可以将可选类型中的值赋给一个常量或者变量。`if``while` 语句,请参考 [控制流](./05_Control_Flow.md)。
像下面这样在 `if` 语句中写一个可选绑定: 像下面这样在 `if` 语句中写一个可选绑定:
@ -570,7 +570,7 @@ if let constantName = someOptional {
} }
``` ```
你可以像上面这样使用可选绑定来重写 在[可选类型](./01_The_Basics.md#optionals)举出的 `possibleNumber` 例子: 你可以像上面这样使用可选绑定来重写 在 [可选类型](./01_The_Basics.md#optionals) 举出的 `possibleNumber` 例子:
```swift ```swift
if let actualNumber = Int(possibleNumber) { if let actualNumber = Int(possibleNumber) {
@ -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} ### 隐式解析可选类型 {#implicityly-unwrapped-optionals}
@ -619,7 +619,7 @@ 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 中类的构造过程中,请参考 [无主引用以及隐式解析可选属性](./23_Automatic_Reference_Counting.md#unowned_references_and_implicitly_unwrapped_optional_properties)。
一个隐式解析可选类型其实就是一个普通的可选类型,但是可以被当做非可选类型来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选类型 `String` 和隐式解析可选类型 `String` 之间的区别: 一个隐式解析可选类型其实就是一个普通的可选类型,但是可以被当做非可选类型来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选类型 `String` 和隐式解析可选类型 `String` 之间的区别:
@ -707,7 +707,7 @@ do {
如果没有错误被抛出,`eatASandwich()` 函数会被调用。如果一个匹配 `SandwichError.outOfCleanDishes` 的错误被抛出,`washDishes()` 函数会被调用。如果一个匹配 `SandwichError.missingIngredients` 的错误被抛出,`buyGroceries(_:)` 函数会被调用,并且使用 `catch` 所捕捉到的关联值 `[String]` 作为参数。 如果没有错误被抛出,`eatASandwich()` 函数会被调用。如果一个匹配 `SandwichError.outOfCleanDishes` 的错误被抛出,`washDishes()` 函数会被调用。如果一个匹配 `SandwichError.missingIngredients` 的错误被抛出,`buyGroceries(_:)` 函数会被调用,并且使用 `catch` 所捕捉到的关联值 `[String]` 作为参数。
抛出,捕捉,以及传播错误会在[错误处理](./17_Error_Handling.md)章节详细说明。 抛出,捕捉,以及传播错误会在 [错误处理](./17_Error_Handling.md) 章节详细说明。
## 断言和先决条件 {#assertions-and-preconditions} ## 断言和先决条件 {#assertions-and-preconditions}
@ -715,7 +715,7 @@ do {
你使用断言和先决条件来表达你所做的假设和你在编码时候的期望。你可以将这些包含在你的代码中。断言帮助你在开发阶段找到错误和不正确的假设,先决条件帮助你在生产环境中探测到存在的问题。 你使用断言和先决条件来表达你所做的假设和你在编码时候的期望。你可以将这些包含在你的代码中。断言帮助你在开发阶段找到错误和不正确的假设,先决条件帮助你在生产环境中探测到存在的问题。
除了在运行时验证你的期望值,断言和先决条件也变成了一个在你的代码中的有用的文档形式。和在上面讨论过的[错误处理](./17_Error_Handling.md)不同,断言和先决条件并不是用来处理可以恢复的或者可预期的错误。因为一个断言失败表明了程序正处于一个无效的状态,没有办法去捕获一个失败的断言。 除了在运行时验证你的期望值,断言和先决条件也变成了一个在你的代码中的有用的文档形式。和在上面讨论过的 [错误处理](./17_Error_Handling.md) 不同,断言和先决条件并不是用来处理可以恢复的或者可预期的错误。因为一个断言失败表明了程序正处于一个无效的状态,没有办法去捕获一个失败的断言。
使用断言和先决条件不是一个能够避免出现程序出现无效状态的编码方法。然而,如果一个无效状态程序产生了,断言和先决条件可以强制检查你的数据和程序状态,使得你的程序可预测的中止(译者:不是系统强制的,被动的中止),并帮助使这个问题更容易调试。一旦探测到无效的状态,执行则被中止,防止无效的状态导致的进一步对于系统的伤害。 使用断言和先决条件不是一个能够避免出现程序出现无效状态的编码方法。然而,如果一个无效状态程序产生了,断言和先决条件可以强制检查你的数据和程序状态,使得你的程序可预测的中止(译者:不是系统强制的,被动的中止),并帮助使这个问题更容易调试。一旦探测到无效的状态,执行则被中止,防止无效的状态导致的进一步对于系统的伤害。
@ -762,7 +762,7 @@ if age > 10 {
precondition(index > 0, "Index must be greater than zero.") precondition(index > 0, "Index must be greater than zero.")
``` ```
你可以调用 `precondition(_:_:file:line:)` 方法来表明出现了一个错误例如switch 进入了 default 分支,但是所有的有效值应该被任意一个其他分支(非 default 分支)处理。 你可以调用 `preconditionFailure(_:file:line:)` 方法来表明出现了一个错误例如switch 进入了 default 分支,但是所有的有效值应该被任意一个其他分支(非 default 分支)处理。
> 注意 > 注意
> >

View File

@ -2,11 +2,11 @@
*运算符*是检查、改变、合并值的特殊符号或短语。例如,加号(`+`)将两个数相加(如 `let i = 1 + 2`)。更复杂的运算例子包括逻辑与运算符 `&&`(如 `if enteredDoorCode && passedRetinaScan`)。 *运算符*是检查、改变、合并值的特殊符号或短语。例如,加号(`+`)将两个数相加(如 `let i = 1 + 2`)。更复杂的运算例子包括逻辑与运算符 `&&`(如 `if enteredDoorCode && passedRetinaScan`)。
Swift 支持大部分标准 C 语言的运算符,且为了减少常见编码错误做了部分改进。如:赋值符(`=`)不再有返回值,这样就消除了手误将判等运算符(`==`)写成赋值符导致代码错误的缺陷。算术运算符(`+``-``*``/``%` 等)的结果会被检测并禁止值溢出,以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然允许你使用 Swift 的溢出运算符来实现溢出。详情参见[溢出运算符](./26_Advanced_Operators.md#overflow_operators)。 Swift 支持大部分标准 C 语言的运算符,且为了减少常见编码错误做了部分改进。如:赋值符(`=`)不再有返回值,这样就消除了手误将判等运算符(`==`)写成赋值符导致代码错误的缺陷。算术运算符(`+``-``*``/``%` 等)的结果会被检测并禁止值溢出,以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然允许你使用 Swift 的溢出运算符来实现溢出。详情参见 [溢出运算符](./26_Advanced_Operators.md#overflow_operators)。
Swift 还提供了 C 语言没有的区间运算符,例如 `a..<b``a...b`,这方便我们表达一个区间内的数值。 Swift 还提供了 C 语言没有的区间运算符,例如 `a..<b``a...b`,这方便我们表达一个区间内的数值。
本章节只描述了 Swift 中的基本运算符,[高级运算符](./26_Advanced_Operators.md)这章会包含 Swift 中的高级运算符,及如何自定义运算符,及如何进行自定义类型的运算符重载。 本章节只描述了 Swift 中的基本运算符,[高级运算符](./26_Advanced_Operators.md) 这章会包含 Swift 中的高级运算符,及如何自定义运算符,及如何进行自定义类型的运算符重载。
## 术语 {#terminology} ## 术语 {#terminology}
@ -62,7 +62,7 @@ Swift 中所有数值类型都支持了基本的四则*算术运算符*
10.0 / 2.5 // 等于 4.0 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`)。详情参见 [溢出运算符](./26_Advanced_Operators.md#overflow_operators)。
加法运算符也可用于 `String` 的拼接: 加法运算符也可用于 `String` 的拼接:
@ -153,7 +153,7 @@ a += 2
> >
> 复合赋值运算没有返回值,`let b = a += 2` 这类代码是错误。这不同于上面提到的自增和自减运算符。 > 复合赋值运算没有返回值,`let b = a += 2` 这类代码是错误。这不同于上面提到的自增和自减运算符。
更多 Swift 标准库运算符的信息,请看[运算符声明](https://developer.apple.com/documentation/swift/operator_declarations)。 更多 Swift 标准库运算符的信息,请看 [运算符声明](https://developer.apple.com/documentation/swift/operator_declarations)。
## 比较运算符Comparison Operators {#comparison-operators} ## 比较运算符Comparison Operators {#comparison-operators}
@ -168,7 +168,7 @@ a += 2
> 注意 > 注意
> >
> Swift 也提供恒等(`===`)和不恒等(`!==`)这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在[类与结构](./09_Classes_and_Structures.md)章节的 **Identity Operators** 部分。 > Swift 也提供恒等(`===`)和不恒等(`!==`)这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在 [类与结构](./09_Classes_and_Structures.md) 章节的 **Identity Operators** 部分。
每个比较运算都返回了一个标识表达式是否成立的布尔值: 每个比较运算都返回了一个标识表达式是否成立的布尔值:
@ -193,7 +193,7 @@ if name == "world" {
// 输出“hello, world", 因为 `name` 就是等于 "world” // 输出“hello, world", 因为 `name` 就是等于 "world”
``` ```
关于 `if` 语句,请看[控制流](./05_Control_Flow.md)。 关于 `if` 语句,请看 [控制流](./05_Control_Flow.md)。
如果两个元组的元素相同,且长度相同的话,元组就可以被比较。比较元组大小会按照从左到右、逐值比较的方式,直到发现有两个值不等时停止。如果所有的值都相等,那么这一对元组我们就称它们是相等的。例如: 如果两个元组的元素相同,且长度相同的话,元组就可以被比较。比较元组大小会按照从左到右、逐值比较的方式,直到发现有两个值不等时停止。如果所有的值都相等,那么这一对元组我们就称它们是相等的。例如:
@ -315,7 +315,7 @@ for index in 1...5 {
// 5 * 5 = 25 // 5 * 5 = 25
``` ```
关于 `for-in` 循环,请看[控制流](./05_Control_Flow.md)。 关于 `for-in` 循环,请看 [控制流](./05_Control_Flow.md)。
### 半开区间运算符 {#half-open-range-operator} ### 半开区间运算符 {#half-open-range-operator}
@ -336,7 +336,7 @@ for i in 0..<count {
// 第 4 个人叫 Jack // 第 4 个人叫 Jack
``` ```
数组有 4 个元素,但 `0..<count` 只数到3最后一个元素的下标因为它是半开区间。关于数组请查阅[数组](./04_Collection_Types.md#arrays)。 数组有 4 个元素,但 `0..<count` 只数到3最后一个元素的下标因为它是半开区间。关于数组请查阅 [数组](./04_Collection_Types.md#arrays)。
### 单侧区间 {#one-sided-ranges} ### 单侧区间 {#one-sided-ranges}

View File

@ -106,11 +106,11 @@ Escaping all three quotes \"\"\"
### 扩展字符串分隔符 {#extended-string-delimiters} ### 扩展字符串分隔符 {#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"###` 也可以实现换行效果。
扩展分隔符创建的字符串文字也可以是多行字符串文字。 您可以使用扩展分隔符在多行字符串中包含文本 **"""**,覆盖原有的结束文字的默认行为。例如: 扩展分隔符创建的字符串文字也可以是多行字符串文字。 您可以使用扩展分隔符在多行字符串中包含文本 `"""`,覆盖原有的结束文字的默认行为。例如:
```swift ```swift
let threeMoreDoubleQuotationMarks = #""" let threeMoreDoubleQuotationMarks = #"""
@ -434,7 +434,7 @@ welcome.removeSubrange(range)
```swift ```swift
let greeting = "Hello, world!" let greeting = "Hello, world!"
let index = greeting.index(of: ",") ?? greeting.endIndex let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index] let beginning = greeting[..<index]
// beginning 的值为 "Hello" // beginning 的值为 "Hello"
@ -458,7 +458,7 @@ Swift 提供了三种方式来比较文本值:字符串字符相等、前缀
### 字符串/字符相等 {#string-and-character-equality} ### 字符串/字符相等 {#string-and-character-equality}
字符串/字符可以用等于操作符(`==`)和不等于操作符(`!=`),详细描述在[比较运算符](./02_Basic_Operators.md#comparison_operators) 字符串/字符可以用等于操作符(`==`)和不等于操作符(`!=`),详细描述在 [比较运算符](./02_Basic_Operators.md#comparison_operators)
```swift ```swift
let quotation = "We're a lot alike, you and I." let quotation = "We're a lot alike, you and I."
@ -556,7 +556,7 @@ 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-representations-of-strings}

View File

@ -1,22 +1,22 @@
# 集合类型 # 集合类型
Swift 语言提供 `Arrays``Sets``Dictionaries` 三种基本的*集合类型*用来存储集合数据。数组Arrays是有序数据的集。集合Sets是无序无重复数据的集。字典Dictionaries是无序的键值对的集。 Swift 语言提供数组(Array、集合Set和字典Dictionary三种基本的*集合类型*用来存储集合数据。数组是有序数据的集。集合是无序无重复数据的集。字典是无序的键值对的集。
![](https://docs.swift.org/swift-book/_images/CollectionTypes_intro_2x.png) ![](https://docs.swift.org/swift-book/_images/CollectionTypes_intro_2x.png)
Swift 语言中的 `Arrays``Sets``Dictionaries` 中存储的数据值类型必须明确。这意味着我们不能把错误数据类型插入其中。同时这也说明你完全可以对取回值的类型非常放心 Swift 中的数组、集合和字典必须明确其中保存的键和值类型,这样就可以避免插入一个错误数据类型的值。同理,对于获取到的值你也可以放心,其数据类型是确定的
> 注意 > 注意
> >
> Swift 的 `Arrays`、`Sets` 和 `Dictionaries` 类型被实现为*泛型集合*。更多关于泛型类型和集合,参见 [泛型](./23_Generics.md)章节。 > Swift 的数组、集合和字典类型被实现为*泛型集合*。更多关于泛型类型和集合,参见 [泛型](./22_Generics.md) 章节。
## 集合的可变性 {#mutability-of-collections} ## 集合的可变性 {#mutability-of-collections}
如果创建一个 `Arrays``Sets``Dictionaries` 并且把它分配成一个变量,这个集合将会是*可变的*。这意味着可以在创建之后添加更多或移除已存在的数据项,或者改变集合中的数据项。如果我们把 `Arrays``Sets``Dictionaries` 分配成常量,那么它就是*不可变的*,它的大小和内容都不能被改变。 如果创建一个数组、集合或字典并且把它分配成一个变量,这个集合将会是*可变的*。这意味着可以在创建之后添加、修改或者删除数据项。如果把数组、集合或字典分配成常量,那么它就是*不可变的*,它的大小和内容都不能被改变。
> 注意 > 注意
> >
> 我们不需要改变集合的时候创建不可变集合是很好的实践。如此 Swift 编译器可以优化我们创建的集合 > 在不需要改变集合的时候创建不可变集合是很好的实践。这样做便于你理解自己的代码,也能让 Swift 编译器优化集合的性能
## 数组Arrays {#arrays} ## 数组Arrays {#arrays}
@ -24,15 +24,17 @@ Swift 语言中的 `Arrays`、`Sets` 和 `Dictionaries` 中存储的数据值类
> 注意 > 注意
> >
> Swift 的 `Array` 类型被桥接到 `Foundation` 中的 `NSArray` 类。更多关于在 `Foundation` 和 `Cocoa` 中使用 `Array` 的信息,参见 [*Using Swift with Cocoa and Obejective-C(Swift 4.1)*](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中[使用 Cocoa 数据类型](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)部分。 > Swift 的 `Array` 类型被桥接到 Foundation 中的 `NSArray` 类。
>
> 更多关于在 Foundation 和 Cocoa 中使用 `Array` 的信息,参见 [Bridging Between Array and NSArray](https://developer.apple.com/documentation/swift/array#2846730)。
### 数组的简单语法 {#array-type-shorthand-syntax} ### 数组的简单语法 {#array-type-shorthand-syntax}
Swift 数组应该遵循像 `Array<Element>` 这样的形式,其中 `Element` 是这个数组中唯一允许存在的数据类型。我们也可以使用像 `[Element]` 这样的简单语法。尽管两种形式在功能上是一样的,但是推荐较短的那种,而且在本文中都会使用这种形式来使用数组。 Swift 数组的完整写法为 `Array<Element>`,其中 `Element` 是这个数组中唯一允许存在的数据类型。也可以使用像 `[Element]` 这样的简单语法。尽管两种形式在功能上是一样的,但是推荐较短的那种,而且在本文中都会使用这种形式来使用数组。
### 创建一个空数组 {#creating-an-empty-array} ### 创建一个空数组 {#creating-an-empty-array}
我们可以使用构造语法来创建一个由特定数据类型构成的空数组: 可以使用构造语法来创建一个由特定数据类型构成的空数组:
```swift ```swift
var someInts = [Int]() var someInts = [Int]()
@ -42,7 +44,7 @@ print("someInts is of type [Int] with \(someInts.count) items.")
注意,通过构造函数的类型,`someInts` 的值类型被推断为 `[Int]` 注意,通过构造函数的类型,`someInts` 的值类型被推断为 `[Int]`
或者,如果代码上下文中已经提供了类型信息,例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:`[]`(一对空方括号): 或者,如果代码上下文中已经提供了类型信息,例如一个函数参数或者一个已经定义好类型的常量或者变量,可以使用空数组语句创建一个空数组,它的写法很简单:`[]`(一对空方括号):
```swift ```swift
someInts.append(3) someInts.append(3)
@ -53,7 +55,7 @@ someInts = []
### 创建一个带有默认值的数组 {#creating-an-array-with-a-default-value} ### 创建一个带有默认值的数组 {#creating-an-array-with-a-default-value}
Swift 中的 `Array` 类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量(`count`)和适当类型的初始值(`repeating`)传入数组构造函数: Swift 中的 `Array` 类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。可以把准备加入新数组的数据项数量(`count`)和适当类型的初始值(`repeating`)传入数组构造函数:
```swift ```swift
var threeDoubles = Array(repeating: 0.0, count: 3) var threeDoubles = Array(repeating: 0.0, count: 3)
@ -62,7 +64,7 @@ var threeDoubles = Array(repeating: 0.0, count: 3)
### 通过两个数组相加创建一个数组 {#creating-an-array-by-adding-two-arrays-together} ### 通过两个数组相加创建一个数组 {#creating-an-array-by-adding-two-arrays-together}
我们可以使用加法操作符(`+`)来组合两已存在的相同类型数组。新数组的数据类型会从两个数组的数据类型中推断出来: 可以使用加法操作符(`+`)来组合两已存在的相同类型数组。新数组的数据类型会从两个数组的数据类型中推断出来:
```swift ```swift
var anotherThreeDoubles = Array(repeating: 2.5, count: 3) var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
@ -74,7 +76,7 @@ var sixDoubles = threeDoubles + anotherThreeDoubles
### 用数组字面量构造数组 {#creating-an-array-with-an-array-literals} ### 用数组字面量构造数组 {#creating-an-array-with-an-array-literals}
我们可以使用*数组字面量*来进行数组构造,这是一种用一个或者多个数值构造数组的简单方法。数组字面量是一系列由逗号分割并由方括号包含的数值: 可以使用*数组字面量*来进行数组构造,这是一种用一个或者多个数值构造数组的简单方法。数组字面量是一系列由逗号分割并由方括号包含的数值:
`[value 1, value 2, value 3]` `[value 1, value 2, value 3]`
@ -85,15 +87,15 @@ var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList 已经被构造并且拥有两个初始项。 // shoppingList 已经被构造并且拥有两个初始项。
``` ```
`shoppingList` 变量被声明为“字符串值类型的数组“,记作 `[String]` 因为这个数组被规定只有 `String` 一种数据结构,所以只有 `String` 类型可以在其中被存取。 在这里,`shoppingList` 数组由两个 `String` 值(`"Eggs"``"Milk"`)构造,并且由数组字面量定义。 `shoppingList` 变量被声明为“字符串值类型的数组“,记作 `[String]`。因为这个数组被规定只有 `String` 一种数据结构,所以只有 `String` 类型可以在其中被存取。在这里,`shoppingList` 数组由两个 `String` 值(`"Eggs"``"Milk"`)构造,并且由数组字面量定义。
> 注意 > 注意
> >
> `shoppingList` 数组被声明为变量(`var` 关键字创建)而不是常量(`let` 创建)是因为以后可能会有更多的数据项被插入其中。 > `shoppingList` 数组被声明为变量(`var` 关键字创建)而不是常量(`let` 创建)是因为之后会有更多的数据项被插入其中。
在这个例子中,字面量仅仅包含两个 `String` 值。匹配了该数组的变量声明(只能包含 `String` 的数组),所以这个字面量的分配过程可以作为用两个初始项来构造 `shoppingList` 的一种方式。 在这个例子中,字面量仅仅包含两个 `String` 值。匹配了该数组的声明(只能包含 `String` 的数组),所以可以将这个字面量的赋值过程看作用两个初始项来构造 `shoppingList` 的一种方式。
由于 Swift 的类型推断机制,当我们用字面量构造拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。`shoppingList` 的构造也可以这样写: 由于 Swift 的类型推断机制,当用字面量构造拥有相同类型值数组的时候,不必把数组的类型定义清楚。`shoppingList` 的构造也可以这样写:
```swift ```swift
var shoppingList = ["Eggs", "Milk"] var shoppingList = ["Eggs", "Milk"]
@ -103,7 +105,7 @@ var shoppingList = ["Eggs", "Milk"]
### 访问和修改数组 {#accessing-and-modifying-an-array} ### 访问和修改数组 {#accessing-and-modifying-an-array}
我们可以通过数组的方法和属性来访问和修改数组,或者使用下标语法。 可以通过数组的方法和属性来访问和修改数组,或者使用下标语法。
可以使用数组的只读属性 `count` 来获取数组中的数据项数量: 可以使用数组的只读属性 `count` 来获取数组中的数据项数量:
@ -127,10 +129,10 @@ if shoppingList.isEmpty {
```swift ```swift
shoppingList.append("Flour") shoppingList.append("Flour")
// shoppingList 现在有3个数据项有人在摊煎饼 // shoppingList 现在有3个数据项似乎有人在摊煎饼
``` ```
除此之外,使用加法赋值运算符(`+=`也可以直接在数组后面添加一个或多个拥有相同类型的数据项: 除此之外,也可以使用加法赋值运算符(`+=`直接将另一个相同类型数组中的数据添加到该数组后面:
```swift ```swift
shoppingList += ["Baking Powder"] shoppingList += ["Baking Powder"]
@ -139,7 +141,7 @@ shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList 现在有七项了 // shoppingList 现在有七项了
``` ```
可以直接使用下标语法来获取数组中的数据项,把我们需要数据项的索引值放在直接放在数组名称的方括号中: 可以直接使用*下标语法*来获取数组中的数据项,把需要数据项的索引值直接放在数组名称之后的方括号中:
```swift ```swift
var firstItem = shoppingList[0] var firstItem = shoppingList[0]
@ -150,13 +152,15 @@ var firstItem = shoppingList[0]
> >
> 第一项在数组中的索引值是 `0` 而不是 `1`。 Swift 中的数组索引总是从零开始。 > 第一项在数组中的索引值是 `0` 而不是 `1`。 Swift 中的数组索引总是从零开始。
我们也可以用下标来改变某个有索引值对应的数据值: 也可以用下标来改变某个有索引值对应的数据值:
```swift ```swift
shoppingList[0] = "Six eggs" shoppingList[0] = "Six eggs"
// 其中的第一项现在是“Six eggs”而不是“Eggs” // 其中的第一项现在是“Six eggs”而不是“Eggs”
``` ```
当你使用下标语法,所使用的下标必须是有效的。例如,试图通过 `shoppingList[shoppingList.count] = "Salt"` 在数组的最后添加一项,将产生一个运行时错误。
还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把 `"Chocolate Spread"``"Cheese"``"Butter"` 替换为 `"Bananas"``"Apples"` 还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把 `"Chocolate Spread"``"Cheese"``"Butter"` 替换为 `"Bananas"``"Apples"`
```swift ```swift
@ -164,11 +168,7 @@ shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList 现在有6项 // shoppingList 现在有6项
``` ```
> 注意 通过调用数组的 `insert(_:at:)` 方法在某个指定索引值之前添加数据项:
>
> 不可以用下标访问的形式去在数组尾部添加新项。
调用数组的 `insert(_:at:)` 方法来在某个具体索引值之前添加数据项:
```swift ```swift
shoppingList.insert("Maple Syrup", at: 0) shoppingList.insert("Maple Syrup", at: 0)
@ -178,18 +178,18 @@ shoppingList.insert("Maple Syrup", at: 0)
这次 `insert(_:at:)` 方法调用把值为 `"Maple Syrup"` 的新数据项插入列表的最开始位置,并且使用 `0` 作为索引值。 这次 `insert(_:at:)` 方法调用把值为 `"Maple Syrup"` 的新数据项插入列表的最开始位置,并且使用 `0` 作为索引值。
类似的我们可以使用 `remove(at:)` 方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(我们不需要的时候就可以无视它): 类似的可以使用 `remove(at:)` 方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(不需要的时候就可以无视它):
```swift ```swift
let mapleSyrup = shoppingList.remove(at: 0) let mapleSyrup = shoppingList.remove(at: 0)
// 索引值为0的数据项被移除 // 索引值为0的数据项被移除
// shoppingList 现在只有6项而且不包括 Maple Syrup // shoppingList 现在只有6项而且不包括 Maple Syrup
// mapleSyrup 常量的值等于被移除数据项“Maple Syrup”的值 // mapleSyrup 常量的值等于被移除数据项“Maple Syrup”
``` ```
> 注意 > 注意
> >
> 如果我们试着对索引越界的数据进行检索或者设置新值的操作,会引发一个运行错误。我们可以使用索引值和数组的 `count` 属性进行比较来在使用某个索引之前检验是否有效。除了当 `count` 等于 0 时(说明这是个空数组),最大索引值一直是 `count - 1`,因为数组都是零起索引。 > 如果你试图通过越界索引来执行访问或者修改数据的操作,会引发一个运行错误。此时可以使用索引值和数组的 `count` 属性进行比较来在使用索引之前检验是否有效。除了当 `count` 等于 0 时(说明这是个空数组),最大索引值一直是 `count - 1`,因为数组都是零起索引。
数据项被移除后数组中的空出项会被自动填补,所以现在索引值为 `0` 的数据项的值再次等于 `"Six eggs"` 数据项被移除后数组中的空出项会被自动填补,所以现在索引值为 `0` 的数据项的值再次等于 `"Six eggs"`
@ -198,18 +198,18 @@ firstItem = shoppingList[0]
// firstItem 现在等于“Six eggs” // firstItem 现在等于“Six eggs”
``` ```
如果我们只想把数组中的最后一项移除,可以使用 `removeLast()` 方法而不是 `remove(at:)` 方法来避免我们需要获取数组的 `count` 属性。就像后者一样,前者也会返回被移除的数据项: 如果只想把数组中的最后一项移除,可以使用 `removeLast()` 方法而不是 `remove(at:)` 方法来避免需要获取数组的 `count` 属性。就像后者一样,前者也会返回被移除的数据项:
```swift ```swift
let apples = shoppingList.removeLast() let apples = shoppingList.removeLast()
// 数组的最后一项被移除了 // 数组的最后一项被移除了
// shoppingList 现在只有5项不包括 Apples // shoppingList 现在只有5项不包括 Apples
// apples 常量的值现在等于“Apples”字符串 // apples 常量的值现在等于字符串“Apples”
``` ```
### 数组的遍历 {#iterating-over-an-array} ### 数组的遍历 {#iterating-over-an-array}
我们可以使用 `for-in` 循环来遍历所有数组中的数据项: 可以使用 `for-in` 循环来遍历数组中所有的数据项:
```swift ```swift
for item in shoppingList { for item in shoppingList {
@ -222,7 +222,7 @@ for item in shoppingList {
// Bananas // Bananas
``` ```
如果我们同时需要每个数据项的值和索引值,可以使用 `enumerated()` 方法来进行数组遍历。`enumerated()` 返回一个由每一个数据项索引值和数据值组成的元组。我们可以把这个元组分解成临时常量或者变量来进行遍历: 如果同时需要每个数据项的值和索引值,可以使用 `enumerated()` 方法来进行数组遍历。`enumerated()` 返回一个由索引值和数据值组成的元组数组。索引值从零开始,并且每次增加一;如果枚举一整个数组,索引值将会和数据值一一匹配。你可以把这个元组分解成临时常量或者变量来进行遍历:
```swift ```swift
for (index, value) in shoppingList.enumerated() { for (index, value) in shoppingList.enumerated() {
@ -235,38 +235,38 @@ for (index, value) in shoppingList.enumerated() {
// Item 5: Bananas // Item 5: Bananas
``` ```
更多关于 `for-in` 循环的介绍请参见[for 循环](05_Control_Flow.html#for_loops)。 更多关于 `for-in` 循环的介绍请参见 [For 循环](05_Control_Flow.html#for_loops)。
## 集合Sets {#sets} ## 集合Sets {#sets}
*集合Set*用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。 *集合*用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。
> 注意 > 注意
> Swift 的 `Set` 类型被桥接到 `Foundation` 中的 `NSSet` 类。 > Swift 的 `Set` 类型被桥接到 Foundation 中的 `NSSet` 类。
> >
> 关于使用 `Foundation``Cocoa` 中 `Set` 的知识,参见 [*Using Swift with Cocoa and Obejective-C(Swift 4.1)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中[使用 Cocoa 数据类型](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)部分。 > 关于使用 Foundation 和 Cocoa 中 `Set` 的知识,参见 [Bridging Between Set and NSSet](https://developer.apple.com/documentation/swift/set#2845530)
### 集合类型的哈希值 {#hash-values-for-set-types} ### 集合类型的哈希值 {#hash-values-for-set-types}
一个类型为了存储在集合中,该类型必须是*可哈希化*的——也就是说,该类型必须提供一个方法来计算它的*哈希值*。一个哈希值是 `Int` 类型的,相等的对象哈希值必须相同,比如 `a==b`,因此必须 `a.hashValue == b.hashValue` 一个类型为了存储在集合中,该类型必须是*可哈希化*的——也就是说,该类型必须提供一个方法来计算它的*哈希值*。一个哈希值是 `Int` 类型的,相等的对象哈希值必须相同,比如 `a == b`,因此必须 `a.hashValue == b.hashValue`
Swift 的所有基本类型(比如 `String``Int``Double``Bool`)默认都是可哈希化的,可以作为集合值的类型或者字典键的类型。没有关联值的枚举成员值(在[枚举](./08_Enumerations.md)有讲述)默认也是可哈希化的。 Swift 的所有基本类型(比如 `String``Int``Double``Bool`)默认都是可哈希化的,可以作为集合值的类型或者字典键的类型。没有关联值的枚举成员值(在 [枚举](./08_Enumerations.md) 有讲述)默认也是可哈希化的。
> 注意 > 注意
> >
> 你可以使用自定义的类型作为集合值的类型或者是字典键的类型,但需要使你的自定义类型遵循 Swift 标准库中的 `Hashable` 协议。遵循 `Hashable` 协议的类型需要提供一个类型为 `Int` 的可读属性 `hashValue`。由类型的 `hashValue` 属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。 > 你可以使用自定义的类型作为集合值的类型或者是字典键的类型,但需要使自定义类型遵循 Swift 标准库中的 `Hashable` 协议。遵循 `Hashable` 协议的类型需要提供一个类型为 `Int` 的可读属性 `hashValue`。由类型的 `hashValue` 属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。
> >
> 因为 `Hashable` 协议遵循 `Equatable` 协议,所以遵循该协议的类型也必须提供一个“是否相等”运算符(`==`)的实现。这个 `Equatable` 协议要求任何遵循 `==` 实现的实例间都是一种相等的关系。也就是说,对于 `a,b,c` 三个值来说,`==` 的实现必须满足下面三种情况: > 因为 `Hashable` 协议遵循 `Equatable` 协议,所以遵循该协议的类型也必须提供一个“是否相等”运算符(`==`)的实现。这个 `Equatable` 协议要求任何遵循 `==` 实现的实例间都是一种相等的关系。也就是说,对于 `a,b,c` 三个值来说,`==` 的实现必须满足下面三种情况:
> * `a == a`(自反性) > * `a == a`(自反性)
> * `a == b` 意味着 `b == a`(对称性) > * `a == b` 意味着 `b == a`(对称性)
> * `a == b && b == c` 意味着 `a == c`(传递性) > * `a == b && b == c` 意味着 `a == c`(传递性)
>
关于遵循协议的更多信息,请看[协议](./22_Protocols.md)。 > 关于遵循协议的更多信息,请看 [协议](./21_Protocols.md)。
### 集合类型语法 {#set-type-syntax} ### 集合类型语法 {#set-type-syntax}
Swift 中的 `Set` 类型被写为 `Set<Element>`,这里的 `Element` 表示 `Set` 中允许存储的类型和数组不同的是,集合没有等价的简化形式。 Swift 中的集合类型被写为 `Set<Element>`,这里的 `Element` 表示集合中允许存储的类型和数组不同的是,集合没有等价的简化形式。
### 创建和构造一个空的集合 {#creating-and-initalizing-an-empty-set} ### 创建和构造一个空的集合 {#creating-and-initalizing-an-empty-set}
@ -280,9 +280,9 @@ print("letters is of type Set<Character> with \(letters.count) items.")
> 注意 > 注意
> >
> 通过构造器,这里 `letters` 变量的类型被推断为 `Set<Character>`。 > 通过构造器,这里 `letters` 变量的类型被推断为 `Set<Character>`。
此外,如果上下文提供了类型信息,比如作为函数的参数或者已知类型的变量或常量,我们可以通过一个空的数组字面量创建一个空的 `Set` 此外,如果上下文提供了类型信息,比如作为函数的参数或者已知类型的变量或常量,可以通过一个空的数组字面量创建一个空的集合
```swift ```swift
letters.insert("a") letters.insert("a")
@ -293,7 +293,7 @@ letters = []
### 用数组字面量创建集合 {#creating-a-set-with-an-array-literal} ### 用数组字面量创建集合 {#creating-a-set-with-an-array-literal}
你可以使用数组字面量来构造集合,并且可以使用简化形式一个或者多个值作为集合元素。 你可以使用数组字面量来构造集合,相当于一种简化形式一个或者多个值作为集合元素。
下面的例子创建一个称之为 `favoriteGenres` 的集合来存储 `String` 类型的值: 下面的例子创建一个称之为 `favoriteGenres` 的集合来存储 `String` 类型的值:
@ -302,13 +302,13 @@ var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres 被构造成含有三个初始值的集合 // favoriteGenres 被构造成含有三个初始值的集合
``` ```
这个 `favoriteGenres` 变量被声明为“一个 `String` 值的集合”,写为 `Set<String>`。由于这个特定集合含有指定 `String` 类型的值,所以它允许存储 `String` 类型值。这里的 `favoriteGenres` 变量有三个 `String` 类型的初始值(`"Rock"``"Classical"``"Hip hop"`以数组字面量的方式出现 这个 `favoriteGenres` 变量被声明为“一个 `String` 值的集合”,写为 `Set<String>`。由于这个特定集合指定了值为 `String` 类型,所以它*只*允许存储 `String` 类型值。这里的 `favoriteGenres` 变量有三个 `String` 类型的初始值(`"Rock"``"Classical"``"Hip hop"`),以数组字面量的形式书写
> 注意 > 注意
> >
> `favoriteGenres` 被声明为一个变量(拥有 `var` 标示符)而不是一个常量(拥有 `let` 标示符),因为它里面的元素将会在下面的例子中被增加或者移除。 > `favoriteGenres` 被声明为一个变量(拥有 `var` 标示符)而不是一个常量(拥有 `let` 标示符),因为它里面的元素将会在之后的例子中被增加或者移除。
一个 `Set` 类型不能从数组字面量中被单独推断出来,因此 `Set` 类型必须显式声明。然而,由于 Swift 的类型推断功能,如果你想使用一个数组字面量构造一个 `Set` 并且该数组字面量中的所有元素类型相同,那么无须写出 `Set` 的具体类型。`favoriteGenres` 的构造形式可以采用简化的方式代替: 一个集合类型不能从数组字面量中被直接推断出来,因此 `Set` 类型必须显式声明。然而,由于 Swift 的类型推断功能,如果你想使用一个数组字面量构造一个集合并且该数组字面量中的所有元素类型相同,那么无须写出集合的具体类型。`favoriteGenres` 的构造形式可以采用简化的方式代替:
```swift ```swift
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"] var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
@ -318,9 +318,9 @@ var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
### 访问和修改一个集合 {#accesing-and-modifying-a-set} ### 访问和修改一个集合 {#accesing-and-modifying-a-set}
你可以通过 `Set` 的属性和方法来访问和修改一个 `Set` 你可以通过集合的属性和方法来对其进行访问和修改。
为了找出一个 `Set` 中元素的数量,可以使用其只读属性 `count` 为了获取一个集合中元素的数量,可以使用其只读属性 `count`
```swift ```swift
print("I have \(favoriteGenres.count) favorite music genres.") print("I have \(favoriteGenres.count) favorite music genres.")
@ -338,14 +338,14 @@ if favoriteGenres.isEmpty {
// 打印“I have particular music preferences.” // 打印“I have particular music preferences.”
``` ```
你可以通过调用 `Set` `insert(_:)` 方法来添加一个新元素: 你可以通过调用集合`insert(_:)` 方法来添加一个新元素:
```swift ```swift
favoriteGenres.insert("Jazz") favoriteGenres.insert("Jazz")
// favoriteGenres 现在包含4个元素 // favoriteGenres 现在包含4个元素
``` ```
你可以通过调用 `Set` `remove(_:)` 方法去删除一个元素,如果该值是该 `Set` 的一个元素则删除该元素并且返回被删除的元素值,否则如果该 `Set` 不包含该值,则返回 `nil`。另外,`Set` 中的所有元素可以通过它的 `removeAll()` 方法删除。 你可以通过调用集合`remove(_:)` 方法去删除一个元素,如果它是该集合的一个元素则删除并且返回它的值,若该集合不包含,则返回 `nil`。另外,集合可以通过 `removeAll()` 方法删除所有元素
```swift ```swift
if let removedGenre = favoriteGenres.remove("Rock") { if let removedGenre = favoriteGenres.remove("Rock") {
@ -356,7 +356,7 @@ if let removedGenre = favoriteGenres.remove("Rock") {
// 打印“Rock? I'm over it.” // 打印“Rock? I'm over it.”
``` ```
使用 `contains(_:)` 方法去检查 `Set` 中是否包含一个特定的值: 使用 `contains(_:)` 方法去检查集合中是否包含一个特定的值:
```swift ```swift
if favoriteGenres.contains("Funk") { if favoriteGenres.contains("Funk") {
@ -369,7 +369,7 @@ if favoriteGenres.contains("Funk") {
### 遍历一个集合 {#iterating-over-a-set} ### 遍历一个集合 {#iterating-over-a-set}
你可以在一个 `for-in` 循环中遍历一个 `Set` 中的所有值。 你可以在一个 `for-in` 循环中遍历一个集合中的所有值。
```swift ```swift
for genre in favoriteGenres { for genre in favoriteGenres {
@ -380,9 +380,9 @@ for genre in favoriteGenres {
// Hip hop // Hip hop
``` ```
更多关于 `for-in` 循环的信息,参见[For 循环](./05_Control_Flow.md#for_loops)。 更多关于 `for-in` 循环的信息,参见 [For 循环](./05_Control_Flow.md#for_loops)。
Swift 的 `Set` 类型没有确定的顺序,为了按照特定顺序来遍历一个 `Set` 中的值可以使用 `sorted()` 方法,它将返回一个有序数组,这个数组的元素排列顺序由操作符'<'对元素进行比较的结果来确定。 Swift 的 `Set` 类型没有确定的顺序,为了按照特定顺序来遍历一个集合中的值可以使用 `sorted()` 方法,它将返回一个有序数组,这个数组的元素排列顺序由操作符 `<` 对元素进行比较的结果来确定。
```swift ```swift
for genre in favoriteGenres.sorted() { for genre in favoriteGenres.sorted() {
@ -395,7 +395,7 @@ for genre in favoriteGenres.sorted() {
## 集合操作 {#performing-set-operations} ## 集合操作 {#performing-set-operations}
你可以高效地完成 `Set` 的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交。 你可以高效地完成集合的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交。
### 基本集合操作 {#fundamental-set-operations} ### 基本集合操作 {#fundamental-set-operations}
@ -403,10 +403,10 @@ for genre in favoriteGenres.sorted() {
![](https://docs.swift.org/swift-book/_images/setVennDiagram_2x.png) ![](https://docs.swift.org/swift-book/_images/setVennDiagram_2x.png)
* 使用 `intersection(_:)` 方法根据两个集合中都包含的值创建一个新的集合。 * 使用 `intersection(_:)` 方法根据两个集合的交集创建一个新的集合。
* 使用 `symmetricDifference(_:)` 方法根据在一个集合中但不在两个集合中的值创建一个新的集合。 * 使用 `symmetricDifference(_:)` 方法根据个集合不相交的值创建一个新的集合。
* 使用 `union(_:)` 方法根据两个集合的值创建一个新的集合。 * 使用 `union(_:)` 方法根据两个集合的所有值创建一个新的集合。
* 使用 `subtracting(_:)` 方法根据不在集合中的值创建一个新的集合。 * 使用 `subtracting(_:)` 方法根据不在另一个集合中的值创建一个新的集合。
```swift ```swift
let oddDigits: Set = [1, 3, 5, 7, 9] let oddDigits: Set = [1, 3, 5, 7, 9]
@ -425,13 +425,13 @@ oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
### 集合成员关系和相等 {#set-membership-and-equality} ### 集合成员关系和相等 {#set-membership-and-equality}
下面的插图描述了三个集合 `a``b``c`,以及通过重叠区域表述集合间共享的元素。集合 `a` 是集合 `b` 的父集合,因为 `a` 包含了 `b` 中所有的元素相反的,集合 `b` 是集合 `a` 的子集合,因为属于 `b` 的元素也被 `a` 包含。集合 `b` 和集合 `c` 彼此不关联,因为它们之间没有共同的元素。 下面的插图描述了三个集合 `a``b``c`以及通过重叠区域表述集合间共享的元素。集合 `a` 是集合 `b`*父集合*,因为 `a` 包含了 `b` 中所有的元素相反的,集合 `b` 是集合 `a`*子集合*,因为属于 `b` 的元素也被 `a` 包含。集合 `b` 和集合 `c` 是*不相交*的,因为它们之间没有共同的元素。
![](https://docs.swift.org/swift-book/_images/setEulerDiagram_2x.png) ![](https://docs.swift.org/swift-book/_images/setEulerDiagram_2x.png)
* 使用“是否相等”运算符(`==`)来判断两个集合是否包含全部相同的值 * 使用“是否相等”运算符(`==`)来判断两个集合包含的值是否全部相同。
* 使用 `isSubset(of:)` 方法来判断一个集合中的值是否也被包含在另外一个集合中。 * 使用 `isSubset(of:)` 方法来判断一个集合中的所有值是否也被包含在另外一个集合中。
* 使用 `isSuperset(of:)` 方法来判断一个集合包含另一个集合中所有的值。 * 使用 `isSuperset(of:)` 方法来判断一个集合是否包含另一个集合中所有的值。
* 使用 `isStrictSubset(of:)` 或者 `isStrictSuperset(of:)` 方法来判断一个集合是否是另外一个集合的子集合或者父集合并且两个集合并不相等。 * 使用 `isStrictSubset(of:)` 或者 `isStrictSuperset(of:)` 方法来判断一个集合是否是另外一个集合的子集合或者父集合并且两个集合并不相等。
* 使用 `isDisjoint(with:)` 方法来判断两个集合是否不含有相同的值(是否没有交集)。 * 使用 `isDisjoint(with:)` 方法来判断两个集合是否不含有相同的值(是否没有交集)。
@ -450,27 +450,27 @@ farmAnimals.isDisjoint(with: cityAnimals)
## 字典 {#dictionaries} ## 字典 {#dictionaries}
*字典*是一种存储多个相同类型的值的容器。每个值value都关联唯一的key键作为字典中这个值数据的标识符。和数组中的数据项不同,字典中的数据项并没有具体顺序。我们在需要通过标识符(键)访问数据的时候使用字典,这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。 *字典*是一种无序的集合,它存储的是键值对之间的关系,其所有键的值需要是相同类型,所有值的类型也需要相同。每个值value都关联唯一的*键*key键作为字典中这个值数据的标识符。和数组中的数据项不同字典中的数据项并没有具体顺序。在需要通过标识符(键)访问数据的时候使用字典,这种方法很大程度上和在现实世界中使用字典查字义的方法一样。
> 注意 > 注意
> >
> Swift 的 `Dictionary` 类型被桥接到 `Foundation` 的 `NSDictionary` 类。 > Swift 的 `Dictionary` 类型被桥接到 Foundation 的 `NSDictionary` 类。
> >
> 更多关于在 `Foundation``Cocoa` 中使用 `Dictionary` 类型的信息,参见 [*Using Swift with Cocoa and Obejective-C(Swift 4.1)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中[使用 Cocoa 数据类型](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)部分 > 更多关于在 Foundation 和 Cocoa 中使用 `Dictionary` 类型的信息,参见 [Bridging Between Dictionary and NSDictionary](https://developer.apple.com/documentation/swift/dictionary#2846239)
### 字典类型简化语法 {#dictionary-type-shorthand-syntax} ### 字典类型简化语法 {#dictionary-type-shorthand-syntax}
Swift 的字典使用 `Dictionary<Key, Value>` 定义,其中 `Key`字典中键的数据类型,`Value` 是字典中对应于这些键所存储值的数据类型。 Swift 的字典使用 `Dictionary<Key, Value>` 定义,其中 `Key`一种可以在字典中被用作键的类型,`Value` 是字典中对应于这些键所存储值的数据类型。
> 注意 > 注意
> >
> 一个字典的 `Key` 类型必须遵循 `Hashable` 协议,就像 `Set` 的值类型。 > 一个字典的 `Key` 类型必须遵循 `Hashable` 协议,就像 `Set` 的值类型。
我们也可以用 `[Key: Value]` 这样简化的形式去创建一个字典类型。虽然这两种形式功能上相同,但是后者是首选,并且这本指导书涉及到字典类型时通篇采用后者。 也可以用 `[Key: Value]` 这样简化的形式去表示字典类型。虽然这两种形式功能上相同,但是后者是首选,并且本教程中涉及到字典类型时通篇采用后者。
### 创建一个空字典 {#creating-an-empty-dictionary} ### 创建一个空字典 {#creating-an-empty-dictionary}
我们可以像数组一样使用构造语法创建一个拥有确定类型的空字典: 可以像数组一样使用构造语法创建一个拥有确定类型的空字典:
```swift ```swift
var namesOfIntegers = [Int: String]() var namesOfIntegers = [Int: String]()
@ -479,7 +479,7 @@ var namesOfIntegers = [Int: String]()
这个例子创建了一个 `[Int: String]` 类型的空字典来储存整数的英语命名。它的键是 `Int` 型,值是 `String` 型。 这个例子创建了一个 `[Int: String]` 类型的空字典来储存整数的英语命名。它的键是 `Int` 型,值是 `String` 型。
如果上下文已经提供了类型信息,我们可以使用空字典字面量来创建一个空字典,记作 `[:]`(中括号中放一个冒号): 如果上下文已经提供了类型信息,可以使用空字典字面量来创建一个空字典,记作 `[:]` (一对方括号中放一个冒号):
```swift ```swift
namesOfIntegers[16] = "sixteen" namesOfIntegers[16] = "sixteen"
@ -490,9 +490,9 @@ namesOfIntegers = [:]
### 用字典字面量创建字典 {#creating-a-dictionary-with-a-dictionary-literal} ### 用字典字面量创建字典 {#creating-a-dictionary-with-a-dictionary-literal}
我们可以使用*字典字面量*来构造字典,这和我们刚才介绍过的数组字面量拥有相似语法。字典字面量是一种将一个或多个键值对写作 `Dictionary` 集合的快捷途径。 可以使用*字典字面量*来构造字典,这和刚才介绍过的数组字面量拥有相似语法。字典字面量是一种将一个或多个键值对写作 `Dictionary` 集合的快捷途径。
一个键值对是一个 `key` 和一个 `value` 的结合体。在字典字面量中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含、由逗号分割: *一个键值对*是一个键和一个值的结合体。在字典字面量中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由逗号分割、并整体被包裹在一对方括号中
```swift ```swift
[key 1: value 1, key 2: value 2, key 3: value 3] [key 1: value 1, key 2: value 2, key 3: value 3]
@ -508,26 +508,26 @@ var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
> 注意 > 注意
> >
> `airports` 字典被声明为变量(用 `var` 关键字)而不是常量(`let` 关键字)因为后更多的机场信息被添加到这个示例字典中。 > `airports` 字典被声明为变量(用 `var` 关键字)而不是常量(`let` 关键字)因为后面会有更多的机场信息被添加到这个字典中。
`airports` 字典使用字典字面量初始化,包含两个键值对。第一对的键是 `YYZ`,值是 `Toronto Pearson`。第二对的键是 `DUB`,值是 `Dublin` `airports` 字典使用字典字面量初始化,包含两个键值对。第一对的键是 `YYZ`,值是 `Toronto Pearson`。第二对的键是 `DUB`,值是 `Dublin`
这个字典语句包含了两个 `String: String` 类型的键值对。它们对应 `airports` 变量声明的类型(一个只有 `String` 键和 `String` 值的字典)所以这个字典字面量的任务是构造拥有两个初始数据项的 `airport` 字典。 这个字典语句包含了两个 `String: String` 类型的键值对。它们对应 `airports` 变量声明的类型(一个只有 `String` 键和 `String` 值的字典)所以这个字典字面量的赋值是一种方式用来构造拥有两个初始数据项的 `airport` 字典。
和数组一样,我们在用字典字面量构造字典时,如果它的键和值都有各自一致的类型,那么就不必写出字典的类型。 和数组一样,在用字典字面量构造字典时,如果它的键和值都有各自一致的类型,那么就不必写出字典的类型。
`airports` 字典也可以用这种简短方式定义: `airports` 字典也可以用这种简短方式定义:
```swift ```swift
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"] var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
``` ```
因为这个语句中所有的键和值都各自拥有相同的数据类型Swift 可以推断出 `Dictionary<String, String>``airports` 字典的正确类型。 因为这个语句中所有的键和值都各自拥有相同的数据类型Swift 可以推断出 `[String: String]``airports` 字典的正确类型。
### 访问和修改字典 {#accessing-and-modifying-a-dictionary} ### 访问和修改字典 {#accessing-and-modifying-a-dictionary}
我们可以通过字典的方法和属性来访问和修改字典,或者通过使用下标语法。 可以通过字典的方法和属性来访问和修改字典,或者通过使用下标语法。
和数组一样,我们可以通过字典的只读属性 `count` 来获取某个字典的数据项数量: 和数组一样,可以通过 `Dictionary` 的只读属性 `count` 来获取字典的数据项数量:
```swift ```swift
print("The dictionary of airports contains \(airports.count) items.") print("The dictionary of airports contains \(airports.count) items.")
@ -545,25 +545,23 @@ if airports.isEmpty {
// 打印“The airports dictionary is not empty.” // 打印“The airports dictionary is not empty.”
``` ```
我们也可以在字典中使用下标语法来添加新的数据项。可以使用一个恰当类型的键作为下标索引,并且分配恰当类型的新值: 你可以通过下标语法来给字典添加新的数据项。可以使用一个恰当类型的键作为下标索引,并且分配恰当类型的新值:
```swift ```swift
airports["LHR"] = "London" airports["LHR"] = "London"
// airports 字典现在有三个数据项 // airports 字典现在有三个数据项
``` ```
我们也可以使用下标语法来改变特定键对应的值: 也可以使用下标语法来改变特定键对应的值:
```swift ```swift
airports["LHR"] = "London Heathrow" airports["LHR"] = "London Heathrow"
// “LHR”对应的值被改为“London Heathrow” // “LHR”对应的值被改为“London Heathrow”
``` ```
作为一种下标方法,字典的 `updateValue(_:forKey:)` 方法可以设置或者更新特定键对应的值。就像上面所示的下标示例,`updateValue(_:forKey:)` 方法在这个键不存在对应值的时候会设置新值或者在存在时更新已存在的值。和上面的下标方法不同`updateValue(_:forKey:)` 这个方法返回更新值之前的原值。这样使得我们可以检查更新是否成功。 作为一种替代下标语法的方式,字典的 `updateValue(_:forKey:)` 方法可以设置或者更新特定键对应的值。就像上面所示的下标示例,`updateValue(_:forKey:)` 方法在这个键不存在对应值的时候会设置新值或者在存在时更新已存在的值。和下标的方式不同,`updateValue(_:forKey:)` 这个方法返回更新值之前的*原值*。这样使得可以检查更新是否成功。
`updateValue(_:forKey:)` 方法会返回对应值类型的可选。举例来说:对于存储 `String` 值的字典,这个函数会返回一个 `String?` 或者“可选 `String`”类型的值。 `updateValue(_:forKey:)` 方法会返回对应值类型的可选类型。举例来说:对于存储 `String` 值的字典,这个函数会返回一个 `String?` 或者“可选 `String`”类型的值。如果有值存在于更新前,则这个可选值包含了旧值,否则它将会是 `nil`
如果有值存在于更新前,则这个可选值包含了旧值,否则它将会是 `nil`
```swift ```swift
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") { if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
@ -572,7 +570,7 @@ if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
// 输出“The old value for DUB was Dublin.” // 输出“The old value for DUB was Dublin.”
``` ```
我们也可以使用下标语法来在字典中检索特定键对应的值。因为有可能请求的键没有对应的值存在,字典的下标访问会返回对应值类型的可选。如果这个字典包含请求键所对应的值,下标会返回一个包含这个存在值的可选,否则将返回 `nil` 也可以使用下标语法来在字典中检索特定键对应的值。因为有可能请求的键没有对应的值存在,字典的下标访问会返回对应值类型的可选类型。如果这个字典包含请求键所对应的值,下标会返回一个包含这个存在值的可选类型,否则将返回 `nil`
```swift ```swift
if let airportName = airports["DUB"] { if let airportName = airports["DUB"] {
@ -583,7 +581,7 @@ if let airportName = airports["DUB"] {
// 打印“The name of the airport is Dublin Airport.” // 打印“The name of the airport is Dublin Airport.”
``` ```
我们还可以使用下标语法通过某个键的对应值赋值为 `nil` 来从字典里移除一个键值对: 还可以使用下标语法通过某个键的对应值赋值为 `nil` 来从字典里移除一个键值对:
```swift ```swift
airports["APL"] = "Apple Internation" airports["APL"] = "Apple Internation"
@ -592,7 +590,7 @@ airports["APL"] = nil
// APL 现在被移除了 // APL 现在被移除了
``` ```
此外,`removeValue(forKey:)` 方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的值或者在没有值的情况下返回 `nil` 此外,`removeValue(forKey:)` 方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的值或者在没有对应值的情况下返回 `nil`
```swift ```swift
if let removedValue = airports.removeValue(forKey: "DUB") { if let removedValue = airports.removeValue(forKey: "DUB") {
@ -605,7 +603,7 @@ if let removedValue = airports.removeValue(forKey: "DUB") {
### 字典遍历 {#iterating-over-a-dictionary} ### 字典遍历 {#iterating-over-a-dictionary}
我们可以使用 `for-in` 循环来遍历某个字典中的键值对。每一个字典中的数据项都以 `(key, value)` 元组形式返回,并且我们可以使用临时常量或者变量来分解这些元组: 可以使用 `for-in` 循环来遍历某个字典中的键值对。每一个字典中的数据项都以 `(key, value)` 元组形式返回,并且可以使用临时常量或者变量来分解这些元组:
```swift ```swift
for (airportCode, airportName) in airports { for (airportCode, airportName) in airports {
@ -615,9 +613,9 @@ for (airportCode, airportName) in airports {
// LHR: London Heathrow // LHR: London Heathrow
``` ```
更多关于 `for-in` 循环的信息,参见[For 循环](./05_Control_Flow.md#for_loops)。 更多关于 `for-in` 循环的信息,参见 [For 循环](./05_Control_Flow.md#for_loops)。
通过访问 `keys` 或者 `values` 属性,我们也可以遍历字典的键或者值: 通过访问 `keys` 或者 `values` 属性,也可以遍历字典的键或者值:
```swift ```swift
for airportCode in airports.keys { for airportCode in airports.keys {
@ -633,7 +631,7 @@ for airportName in airports.values {
// Airport name: London Heathrow // Airport name: London Heathrow
``` ```
如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受 `Array` 实例的 API 的参数,可以直接使用 `keys` 或者 `values` 属性构造一个新数组: 如果需要使用某个字典的键集合或者值集合来作为某个接受 `Array` 实例的 API 的参数,可以直接使用 `keys` 或者 `values` 属性构造一个新数组:
```swift ```swift
let airportCodes = [String](airports.keys) let airportCodes = [String](airports.keys)
@ -643,4 +641,4 @@ let airportNames = [String](airports.values)
// airportNames 是 ["Toronto Pearson", "London Heathrow"] // airportNames 是 ["Toronto Pearson", "London Heathrow"]
``` ```
Swift 的字典类型是无序集合类型。为了以特定的顺序遍历字典的键或值,可以对字典的 `keys``values` 属性使用 `sorted()` 方法。 Swift 的 `Dictionary` 是无序集合类型。为了以特定的顺序遍历字典的键或值,可以对字典的 `keys``values` 属性使用 `sorted()` 方法。

View File

@ -30,12 +30,12 @@ let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs { for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs") print("\(animalName)s have \(legCount) legs")
} }
// cats have 4 legs
// ants have 6 legs // ants have 6 legs
// spiders have 8 legs // spiders have 8 legs
// cats have 4 legs
``` ```
字典的内容理论上是无序的,遍历元素时的顺序是无法确定的。将元素插入字典的顺序并不会决定它们被遍历的顺序。关于数组和字典的细节,参见[集合类型](./04_Collection_Types.md)。 字典的内容理论上是无序的,遍历元素时的顺序是无法确定的。将元素插入字典的顺序并不会决定它们被遍历的顺序。关于数组和字典的细节,参见 [集合类型](./04_Collection_Types.md)。
`for-in` 循环还可以使用数字范围。下面的例子用来输出乘法表的一部分内容: `for-in` 循环还可以使用数字范围。下面的例子用来输出乘法表的一部分内容:
@ -69,7 +69,7 @@ print("\(base) to the power of \(power) is \(answer)")
这个例子计算 base 这个数的 power 次幂(本例中,是 `3``10` 次幂),从 `1``3``0` 次幂)开始做 `3` 的乘法, 进行 `10` 次,使用 `1``10` 的闭区间循环。这个计算并不需要知道每一次循环中计数器具体的值,只需要执行了正确的循环次数即可。下划线符号 `_` (替代循环中的变量)能够忽略当前值,并且不提供循环遍历时对值的访问。 这个例子计算 base 这个数的 power 次幂(本例中,是 `3``10` 次幂),从 `1``3``0` 次幂)开始做 `3` 的乘法, 进行 `10` 次,使用 `1``10` 的闭区间循环。这个计算并不需要知道每一次循环中计数器具体的值,只需要执行了正确的循环次数即可。下划线符号 `_` (替代循环中的变量)能够忽略当前值,并且不提供循环遍历时对值的访问。
在某些情况下,你可能不想使用包括两个端点的闭区间。想象一下,你在一个手表上绘制分钟的刻度线。总共 `60` 个刻度,从 `0` 分开始。使用半开区间运算符(`..<`)来表示一个左闭右开的区间。有关区间的更多信息,请参阅[区间运算符](./02_Basic_Operators.md#range_operators)。 在某些情况下,你可能不想使用包括两个端点的闭区间。想象一下,你在一个手表上绘制分钟的刻度线。总共 `60` 个刻度,从 `0` 分开始。使用半开区间运算符(`..<`)来表示一个左闭右开的区间。有关区间的更多信息,请参阅 [区间运算符](./02_Basic_Operators.md#range_operators)。
```swift ```swift
let minutes = 60 let minutes = 60
@ -324,7 +324,7 @@ default:
// 输出“The last letter of the alphabet” // 输出“The last letter of the alphabet”
``` ```
在这个例子中,第一个 case 分支用于匹配第一个英文字母 `a`,第二个 case 分支用于匹配最后一个字母 `z`。因为 `switch` 语句必须有一个 case 分支用于覆盖所有可能的字符,而不仅仅是所有的英文字母,所以 switch 语句使用 `default` 分支来匹配除了 `a``z` 外的所有值,这个分支保证了 swith 语句的完备性。 在这个例子中,第一个 case 分支用于匹配第一个英文字母 `a`,第二个 case 分支用于匹配最后一个字母 `z`。因为 `switch` 语句必须有一个 case 分支用于覆盖所有可能的字符,而不仅仅是所有的英文字母,所以 switch 语句使用 `default` 分支来匹配除了 `a``z` 外的所有值,这个分支保证了 switch 语句的完备性。
#### 不存在隐式的贯穿 {#no-implicit-fallthrough} #### 不存在隐式的贯穿 {#no-implicit-fallthrough}
@ -332,7 +332,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 分支是空的: 每一个 case 分支都*必须*包含至少一条语句。像下面这样书写代码是无效的,因为第一个 case 分支是空的:
@ -363,11 +363,11 @@ default:
// 输出“The letter A” // 输出“The letter A”
``` ```
为了可读性,符合匹配可以写成多行形式,详情请参考[复合匹配](#compound_cases) 为了可读性,符合匹配可以写成多行形式,详情请参考 [复合匹配](#compound_cases)
> 注意 > 注意
> >
> 如果想要显式贯穿 case 分支,请使用 `fallthrough` 语句,详情请参考[贯穿](#fallthrough)。 > 如果想要显式贯穿 case 分支,请使用 `fallthrough` 语句,详情请参考 [贯穿](#fallthrough)。
#### 区间匹配 {#interval-matching} #### 区间匹配 {#interval-matching}
@ -527,7 +527,7 @@ default:
- `return` - `return`
- `throw` - `throw`
我们将会在下面讨论 `continue``break``fallthrough` 语句。`return` 语句将会在[函数](./06_Functions.md)章节讨论,`throw` 语句会在[错误抛出](./18_Error_Handling.md#throwing_errors)章节讨论。 我们将会在下面讨论 `continue``break``fallthrough` 语句。`return` 语句将会在 [函数](./06_Functions.md) 章节讨论,`throw` 语句会在 [错误抛出](./18_Error_Handling.md#throwing_errors) 章节讨论。
### Continue {#continue} ### Continue {#continue}
@ -754,7 +754,7 @@ if #available(iOS 10, macOS 10.12, *) {
以上可用性条件指定,`if` 语句的代码块仅仅在 iOS 10 或 macOS 10.12 及更高版本才运行。最后一个参数,`*`是必须的用于指定在所有其它平台中如果版本号高于你的设备指定的最低版本if 语句的代码块将会运行。 以上可用性条件指定,`if` 语句的代码块仅仅在 iOS 10 或 macOS 10.12 及更高版本才运行。最后一个参数,`*`是必须的用于指定在所有其它平台中如果版本号高于你的设备指定的最低版本if 语句的代码块将会运行。
在它一般的形式中,可用性条件使用了一个平台名字和版本的列表。平台名字可以是 `iOS``macOS``watchOS``tvOS`——请访问[声明属性](../chapter3/06_Attributes.html)来获取完整列表。除了指定像 iOS 8 或 macOS 10.10 的大版本号,也可以指定像 iOS 11.2.6 以及 macOS 10.13.3 的小版本号。 在它一般的形式中,可用性条件使用了一个平台名字和版本的列表。平台名字可以是 `iOS``macOS``watchOS``tvOS`——请访问 [声明属性](../chapter3/06_Attributes.html) 来获取完整列表。除了指定像 iOS 8 或 macOS 10.10 的大版本号,也可以指定像 iOS 11.2.6 以及 macOS 10.13.3 的小版本号。
```swift ```swift
if #available(平台名称 版本号, ..., *) { if #available(平台名称 版本号, ..., *) {

View File

@ -202,6 +202,30 @@ if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
// 打印“min is -6 and max is 109” // 打印“min is -6 and max is 109”
``` ```
### 隐式返回的函数 {#functions-with-an-implicit-return}
如果一个函数的整个函数体是一个单行表达式,这个函数可以隐式地返回这个表达式。举个例子,以下的函数有着同样的作用:
```
func greeting(for person: String) -> String {
"Hello, " + person + "!"
}
print(greeting(for: "Dave"))
// 打印 "Hello, Dave!"
func anotherGreeting(for person: String) -> String {
return "Hello, " + person + "!"
}
print(anotherGreeting(for: "Dave"))
// 打印 "Hello, Dave!"
```
`greeting(for:)` 函数的完整定义是打招呼内容的返回,这就意味着它能使用隐式返回这样更简短的形式。`anothergreeting(for:)` 函数返回同样的内容,却因为 `return` 关键字显得函数更长。任何一个可以被写成一行 `return` 语句的函数都可以忽略 `return`
正如你将会在 [简略的 Getter 声明](./10_Properties.md) 里看到的, 一个属性的 getter 也可以使用隐式返回的形式。
## 函数参数标签和参数名称 {#Function-Argument-Labels-and-Parameter-Names} ## 函数参数标签和参数名称 {#Function-Argument-Labels-and-Parameter-Names}
每个函数参数都有一个*参数标签argument label*以及一个*参数名称parameter name*。参数标签在调用函数的时候使用;调用的时候需要将函数的参数标签写在对应的参数前面。参数名称在函数的实现中使用。默认情况下,函数参数使用参数名称来作为它们的参数标签。 每个函数参数都有一个*参数标签argument label*以及一个*参数名称parameter name*。参数标签在调用函数的时候使用;调用的时候需要将函数的参数标签写在对应的参数前面。参数名称在函数的实现中使用。默认情况下,函数参数使用参数名称来作为它们的参数标签。
@ -294,7 +318,7 @@ arithmeticMean(3, 8.25, 18.75)
函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为*输入输出参数In-Out Parameters*。 函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为*输入输出参数In-Out Parameters*。
定义一个输入输出参数时,在参数定义前加 `inout` 关键字。一个 `输入输出参数`有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。想获取更多的关于输入输出参数的细节和相关的编译器优化,请查看[输入输出参数](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID545)一节。 定义一个输入输出参数时,在参数定义前加 `inout` 关键字。一个 `输入输出参数`有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。想获取更多的关于输入输出参数的细节和相关的编译器优化,请查看 [输入输出参数](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID545) 一节。
你只能传递变量给输入输出参数。你不能传入常量或者字面量,因为这些量是不能被修改的。当传入的参数作为输入输出参数时,需要在参数名前加 `&` 符,表示这个值可以被函数修改。 你只能传递变量给输入输出参数。你不能传入常量或者字面量,因为这些量是不能被修改的。当传入的参数作为输入输出参数时,需要在参数名前加 `&` 符,表示这个值可以被函数修改。

View File

@ -6,9 +6,9 @@
> 注意 > 注意
> >
> 如果你不熟悉捕获capturing这个概念也不用担心在[值捕获](#capturing_values)章节有它更详细的介绍。 > 如果你不熟悉捕获capturing这个概念也不用担心 [值捕获](#capturing_values) 章节有它更详细的介绍。
在[函数](./06_Functions.md)章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采用如下三种形式之一: [函数](./06_Functions.md) 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采用如下三种形式之一:
* 全局函数是一个有名字但不会捕获任何值的闭包 * 全局函数是一个有名字但不会捕获任何值的闭包
* 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包 * 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包
@ -23,7 +23,7 @@ Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进
## 闭包表达式 {#closure-expressions} ## 闭包表达式 {#closure-expressions}
[嵌套函数](./06_Functions.md#Nested_Functions)作为复杂函数的一部分时,它自包含代码块式的定义和命名形式在使用上带来了方便。当然,编写未完整声明和没有函数名的类函数结构代码是很有用的,尤其是在编码中涉及到函数作为参数的那些方法时。 [嵌套函数](./06_Functions.md#Nested_Functions) 作为复杂函数的一部分时,它自包含代码块式的定义和命名形式在使用上带来了方便。当然,编写未完整声明和没有函数名的类函数结构代码是很有用的,尤其是在编码中涉及到函数作为参数的那些方法时。
*闭包表达式*是一种构建内联闭包的方式,它的语法简洁。在保证不丢失它语法清晰明了的同时,闭包表达式提供了几种优化的语法简写形式。下面通过对 `sorted(by:)` 这一个案例的多次迭代改进来展示这个过程,每次迭代都使用了更加简明的方式描述了相同功能。。 *闭包表达式*是一种构建内联闭包的方式,它的语法简洁。在保证不丢失它语法清晰明了的同时,闭包表达式提供了几种优化的语法简写形式。下面通过对 `sorted(by:)` 这一个案例的多次迭代改进来展示这个过程,每次迭代都使用了更加简明的方式描述了相同功能。。
@ -129,7 +129,7 @@ reversedNames = names.sorted(by: { $0 > $1 } )
reversedNames = names.sorted(by: >) reversedNames = names.sorted(by: >)
``` ```
更多关于运算符方法的内容请查看[运算符方法](./26_Advanced_Operators.md#operator_methods)。 更多关于运算符方法的内容请查看 [运算符方法](./26_Advanced_Operators.md#operator_methods)。
## 尾随闭包 {#trailing-closures} ## 尾随闭包 {#trailing-closures}
@ -151,7 +151,7 @@ someFunctionThatTakesAClosure() {
} }
``` ```
在[闭包表达式语法](#closure_expression_syntax)上章节中的字符串排序闭包可以作为尾随包的形式改写在 `sorted(by:)` 方法圆括号的外面: [闭包表达式语法](#closure_expression_syntax) 上章节中的字符串排序闭包可以作为尾随包的形式改写在 `sorted(by:)` 方法圆括号的外面:
```swift ```swift
reversedNames = names.sorted() { $0 > $1 } 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` 的返回值。 `makeIncrementer(forIncrement:)` 函数定义了一个初始值为 `0` 的整型变量 `runningTotal`,用来存储当前总计数值。该值为 `incrementer` 的返回值。
@ -290,7 +290,7 @@ incrementByTen()
> 注意 > 注意
> >
> 如果你将闭包赋值给一个类实例的属性并且该闭包通过访问该实例或其成员而捕获了该实例你将在闭包和该实例间创建一个循环强引用。Swift 使用捕获列表来打破这种循环强引用。更多信息,请参考[闭包引起的循环强引用](./23_Automatic_Reference_Counting.md#strong_reference_cycles_for_closures)。 > 如果你将闭包赋值给一个类实例的属性并且该闭包通过访问该实例或其成员而捕获了该实例你将在闭包和该实例间创建一个循环强引用。Swift 使用捕获列表来打破这种循环强引用。更多信息,请参考 [闭包引起的循环强引用](./23_Automatic_Reference_Counting.md#strong_reference_cycles_for_closures)。
## 闭包是引用类型 {#closures-are-reference-types} ## 闭包是引用类型 {#closures-are-reference-types}
@ -397,7 +397,7 @@ serve(customer: customersInLine.remove(at: 0))
> >
> 过度使用 `autoclosures` 会让你的代码变得难以理解。上下文和函数名应该能够清晰地表明求值是被延迟执行的。 > 过度使用 `autoclosures` 会让你的代码变得难以理解。上下文和函数名应该能够清晰地表明求值是被延迟执行的。
如果你想让一个自动闭包可以“逃逸”,则应该同时使用 `@autoclosure``@escaping` 属性。`@escaping` 属性的讲解见上面的[逃逸闭包](#escaping_closures)。 如果你想让一个自动闭包可以“逃逸”,则应该同时使用 `@autoclosure``@escaping` 属性。`@escaping` 属性的讲解见上面的 [逃逸闭包](#escaping_closures)。
```swift ```swift
// customersInLine i= ["Barry", "Daniella"] // customersInLine i= ["Barry", "Daniella"]

View File

@ -8,7 +8,7 @@
在 Swift 中枚举类型是一等first-class类型。它们采用了很多在传统上只被类class所支持的特性例如计算属性computed properties用于提供枚举值的附加信息实例方法instance methods用于提供和枚举值相关联的功能。枚举也可以定义构造函数initializers来提供一个初始值可以在原始实现的基础上扩展它们的功能还可以遵循协议protocols来提供标准的功能。 在 Swift 中枚举类型是一等first-class类型。它们采用了很多在传统上只被类class所支持的特性例如计算属性computed properties用于提供枚举值的附加信息实例方法instance methods用于提供和枚举值相关联的功能。枚举也可以定义构造函数initializers来提供一个初始值可以在原始实现的基础上扩展它们的功能还可以遵循协议protocols来提供标准的功能。
想了解更多相关信息,请参见[属性](./10_Properties.md)[方法](./11_Methods.md)[构造过程](./14_Initialization.md)[扩展](./20_Extensions.md)[协议](./21_Protocols.md)。 想了解更多相关信息,请参见 [属性](./10_Properties.md)[方法](./11_Methods.md)[构造过程](./14_Initialization.md)[扩展](./20_Extensions.md)[协议](./21_Protocols.md)。
## 枚举语法 {#enumeration-syntax} ## 枚举语法 {#enumeration-syntax}
@ -84,7 +84,7 @@ case .west:
……以此类推。 ……以此类推。
正如在[控制流](./05_Control_Flow.md)中介绍的那样,在判断一个枚举类型的值时,`switch` 语句必须穷举所有情况。如果忽略了 `.west` 这种情况,上面那段代码将无法通过编译,因为它没有考虑到 `CompassPoint` 的全部成员。强制穷举确保了枚举成员不会被意外遗漏。 正如在 [控制流](./05_Control_Flow.md) 中介绍的那样,在判断一个枚举类型的值时,`switch` 语句必须穷举所有情况。如果忽略了 `.west` 这种情况,上面那段代码将无法通过编译,因为它没有考虑到 `CompassPoint` 的全部成员。强制穷举确保了枚举成员不会被意外遗漏。
当不需要匹配每个枚举成员的时候,你可以提供一个 `default` 分支来涵盖所有未明确处理的枚举成员: 当不需要匹配每个枚举成员的时候,你可以提供一个 `default` 分支来涵盖所有未明确处理的枚举成员:
@ -125,7 +125,7 @@ for beverage in Beverage.allCases {
// juice // juice
``` ```
在前面的例子中,使用的语法表明这个枚举遵循 [CaseIterable](https://developer.apple.com/documentation/swift/caseiterable) 协议。想了解 protocols 相关信息,请参见[协议](./21_Protocols.md)。 在前面的例子中,使用的语法表明这个枚举遵循 [CaseIterable](https://developer.apple.com/documentation/swift/caseiterable) 协议。想了解 protocols 相关信息,请参见 [协议](./21_Protocols.md)。
## 关联值 {#associated-values} ## 关联值 {#associated-values}
@ -200,7 +200,7 @@ case let .qrCode(productCode):
## 原始值 {#raw-values} ## 原始值 {#raw-values}
在[关联值](#associated_values)小节的条形码例子中,演示了如何声明存储不同类型关联值的枚举成员。作为关联值的替代选择,枚举成员可以被默认值(称为*原始值*)预填充,这些原始值的类型必须相同。 [关联值](#associated_values) 小节的条形码例子中,演示了如何声明存储不同类型关联值的枚举成员。作为关联值的替代选择,枚举成员可以被默认值(称为*原始值*)预填充,这些原始值的类型必须相同。
这是一个使用 ASCII 码作为原始值的枚举: 这是一个使用 ASCII 码作为原始值的枚举:
@ -212,7 +212,7 @@ enum ASCIIControlCharacter: Character {
} }
``` ```
枚举类型 `ASCIIControlCharacter` 的原始值类型被定义为 `Character`,并设置了一些比较常见的 ASCII 控制字符。`Character` 的描述详见[字符串和字符](./03_Strings_and_Characters.md)部分。 枚举类型 `ASCIIControlCharacter` 的原始值类型被定义为 `Character`,并设置了一些比较常见的 ASCII 控制字符。`Character` 的描述详见 [字符串和字符](./03_Strings_and_Characters.md) 部分。
原始值可以是字符串、字符,或者任意整型值或浮点型值。每个原始值在枚举声明中必须是唯一的。 原始值可以是字符串、字符,或者任意整型值或浮点型值。每个原始值在枚举声明中必须是唯一的。
@ -273,7 +273,7 @@ let possiblePlanet = Planet(rawValue: 7)
> 注意 > 注意
> >
> 原始值构造器是一个可失败构造器,因为并不是每一个原始值都有与之对应的枚举成员。更多信息请参见[可失败构造器](../chapter3/05_Declarations.html#failable_initializers) > 原始值构造器是一个可失败构造器,因为并不是每一个原始值都有与之对应的枚举成员。更多信息请参见 [可失败构造器](../chapter3/05_Declarations.html#failable_initializers)
如果你试图寻找一个位置为 `11` 的行星,通过原始值构造器返回的可选 `Planet` 值将是 `nil` 如果你试图寻找一个位置为 `11` 的行星,通过原始值构造器返回的可选 `Planet` 值将是 `nil`

View File

@ -47,7 +47,7 @@ class SomeClass {
> 注意 > 注意
> >
> 每当你定义一个新的结构体或者类时,你都是定义了一个新的 Swift 类型。请使用 `UpperCamelCase` 这种方式来命名类型(如这里的 `SomeClass` 和 `SomeStructure`),以便符合标准 Swift 类型的大写命名风格(如 `String``Int` 和 `Bool`)。请使用 `lowerCamelCase` 这种方式来命名属性和方法(如 `framerate` 和 `incrementCount`),以便和类型名区分。 > 每当你定义一个新的结构体或者类时,你都是定义了一个新的 Swift 类型。请使用 `UpperCamelCase` 这种方式来命名类型(如这里的 `SomeClass` 和 `SomeStructure`),以便符合标准 Swift 类型的大写命名风格(如 `String``Int` 和 `Bool`)。请使用 `lowerCamelCase` 这种方式来命名属性和方法(如 `frameRate` 和 `incrementCount`),以便和类型名区分。
以下是定义结构体和定义类的示例: 以下是定义结构体和定义类的示例:

View File

@ -10,7 +10,7 @@
简单来说,一个存储属性就是存储在特定类或结构体实例里的一个常量或变量。存储属性可以是*变量存储属性*(用关键字 `var` 定义),也可以是*常量存储属性*(用关键字 `let` 定义)。 简单来说,一个存储属性就是存储在特定类或结构体实例里的一个常量或变量。存储属性可以是*变量存储属性*(用关键字 `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` 的结构体,该结构体用于描述整数的区间,且这个范围值在被创建后不能被修改。 下面的例子定义了一个名为 `FixedLengthRange` 的结构体,该结构体用于描述整数的区间,且这个范围值在被创建后不能被修改。
@ -174,6 +174,28 @@ struct AlternativeRect {
} }
``` ```
### 简化 Getter 声明 {#shorthand-getter-declaration}
如果整个 getter 是单一表达式getter 会隐式地返回这个表达式结果。下面是另一个版本的 `Rect` 结构体,用到了简化的 getter 和 setter 声明:
```swift
struct CompactRect {
var origin = Point()
var size = Size()
var center: Point {
get {
Point(x: origin.x + (size.width / 2),
y: origin.y + (size.height / 2))
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
```
在 getter 中忽略 `return` 与在函数中忽略 `return` 的规则相同,请参考 [隐式返回的函数](./06_Functions.md/#functions-with-an-implicit-return)。
### 只读计算属性 {#readonly-computed-properties} ### 只读计算属性 {#readonly-computed-properties}
只有 getter 没有 setter 的计算属性叫*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。 只有 getter 没有 setter 的计算属性叫*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。
@ -202,7 +224,7 @@ print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。 属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。
你可以为除了延时加载存储属性之外的其他存储属性添加属性观察器,你也可以在子类中通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。你不必为非重写的计算属性添加属性观察器,因为你可以直接通过它的 setter 监控和响应值的变化。属性重写请参考[重写](./13_Inheritance.md#overriding)。 你可以为除了延时加载存储属性之外的其他存储属性添加属性观察器,你也可以在子类中通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。你不必为非重写的计算属性添加属性观察器,因为你可以直接通过它的 setter 监控和响应值的变化。属性重写请参考 [重写](./13_Inheritance.md#overriding)。
可以为属性添加其中一个或两个观察器: 可以为属性添加其中一个或两个观察器:
@ -217,7 +239,7 @@ print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
> >
> 在父类初始化方法调用之后,在子类构造器中给父类的属性赋值时,会调用父类属性的 `willSet` 和 `didSet` 观察器。而在父类初始化方法调用之前,给子类的属性赋值时不会调用子类属性的观察器。 > 在父类初始化方法调用之后,在子类构造器中给父类的属性赋值时,会调用父类属性的 `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` 的类,用来统计一个人步行时的总步数。这个类可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。 下面是一个 `willSet``didSet` 实际运用的例子,其中定义了一个名为 `StepCounter` 的类,用来统计一个人步行时的总步数。这个类可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。
@ -256,7 +278,7 @@ 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 参数详细的介绍,请参考 [输入输出参数](../chapter3/05_Declarations.html#in-out_parameters)
## 全局变量和局部变量 {#global-and-local-variables} ## 全局变量和局部变量 {#global-and-local-variables}
@ -268,7 +290,7 @@ stepCounter.totalSteps = 896
> 注意 > 注意
> >
> 全局的常量或变量都是延迟计算的,跟[延时加载存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记 `lazy` 修饰符。 > 全局的常量或变量都是延迟计算的,跟 [延时加载存储属性](#lazy_stored_properties) 相似,不同的地方在于,全局的常量或变量不需要标记 `lazy` 修饰符。
> >
> 局部范围的常量和变量从不延迟计算。 > 局部范围的常量和变量从不延迟计算。

View File

@ -6,7 +6,7 @@
## 实例方法Instance Methods {#instance-methods} ## 实例方法Instance Methods {#instance-methods}
*实例方法*是属于某个特定类、结构体或者枚举类型实例的方法。实例方法提供访问和修改实例属性的方法或提供与实例目的相关的功能,并以此来支撑实例的功能。实例方法的语法与函数完全一致,详情参见[函数](./06_Functions.md)。 *实例方法*是属于某个特定类、结构体或者枚举类型实例的方法。实例方法提供访问和修改实例属性的方法或提供与实例目的相关的功能,并以此来支撑实例的功能。实例方法的语法与函数完全一致,详情参见 [函数](./06_Functions.md)。
实例方法要写在它所属的类型的前后大括号之间。实例方法能够隐式访问它所属类型的所有的其他实例方法和属性。实例方法只能被它所属的类的某个特定实例调用。实例方法不能脱离于现存的实例而被调用。 实例方法要写在它所属的类型的前后大括号之间。实例方法能够隐式访问它所属类型的所有的其他实例方法和属性。实例方法只能被它所属的类的某个特定实例调用。实例方法不能脱离于现存的实例而被调用。
@ -47,7 +47,7 @@ counter.reset()
// 计数值现在是0 // 计数值现在是0
``` ```
函数参数可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用),详情参见[指定外部参数名](./06_Functions.md#specifying_external_parameter_names)。方法参数也一样,因为方法就是函数,只是这个函数与某个类型相关联了。 函数参数可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用),详情参见 [指定外部参数名](./06_Functions.md#specifying_external_parameter_names)。方法参数也一样,因为方法就是函数,只是这个函数与某个类型相关联了。
### self 属性 {#the-self-property} ### self 属性 {#the-self-property}
@ -107,7 +107,7 @@ print("The point is now at (\(somePoint.x), \(somePoint.y))")
上面的 `Point` 结构体定义了一个可变方法 `moveByxy :)` 来移动 `Point` 实例到给定的位置。该方法被调用时修改了这个点,而不是返回一个新的点。方法定义时加上了 `mutating` 关键字,从而允许修改属性。 上面的 `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 ```swift
let fixedPoint = Point(x: 3.0, y: 3.0) let fixedPoint = Point(x: 3.0, y: 3.0)
@ -157,7 +157,7 @@ ovenLight.next()
## 类型方法 {#type-methods} ## 类型方法 {#type-methods}
实例方法是被某个类型的实例调用的方法。你也可以定义在类型本身上调用的方法,这种方法就叫做*类型方法*。在方法的 `func` 关键字之前加上关键字 `static`,来指定类型方法。类还可以用关键字 `class` 来允许子类重写父类方法实现。 实例方法是被某个类型的实例调用的方法。你也可以定义在类型本身上调用的方法,这种方法就叫做*类型方法*。在方法的 `func` 关键字之前加上关键字 `static`,来指定类型方法。类还可以用关键字 `class`指定,从而允许子类重写父类方法实现。
> 注意 > 注意
> >
@ -213,7 +213,7 @@ struct LevelTracker {
除了类型属性和类型方法,`LevelTracker` 还监测每个玩家的进度。它用实例属性 `currentLevel` 来监测每个玩家当前的等级。 除了类型属性和类型方法,`LevelTracker` 还监测每个玩家的进度。它用实例属性 `currentLevel` 来监测每个玩家当前的等级。
为了便于管理 `currentLevel` 属性,`LevelTracker` 定义了实例方法 `advance(to:)`。这个方法会在更新 `currentLevel` 之前检查所请求的新等级是否已经解锁。`advance(to:)` 方法返回布尔值以指示是否能够设置 `currentLevel`。因为允许在调用 `advance(to:)` 时候忽略返回值,不会产生编译警告,所以函数被标注为 `@discardableResult` 属性,更多关于属性信息,请参考[特性](../chapter3/07_Attributes.html)章节。 为了便于管理 `currentLevel` 属性,`LevelTracker` 定义了实例方法 `advance(to:)`。这个方法会在更新 `currentLevel` 之前检查所请求的新等级是否已经解锁。`advance(to:)` 方法返回布尔值以指示是否能够设置 `currentLevel`。因为允许在调用 `advance(to:)` 时候忽略返回值,不会产生编译警告,所以函数被标注为 `@discardableResult` 属性,更多关于属性信息,请参考 [特性](../chapter3/07_Attributes.html)章节。
下面,`Player` 类使用 `LevelTracker` 来监测和更新每个玩家的发展进度: 下面,`Player` 类使用 `LevelTracker` 来监测和更新每个玩家的发展进度:

View File

@ -72,7 +72,7 @@ numberOfLegs["bird"] = 2
## 下标选项 {#subscript-options} ## 下标选项 {#subscript-options}
下标可以接受任意数量的入参,并且这些入参可以是任意类型。下标的返回值也可以是任意类型。下标可以使用变量参数和可变参数,但不能使用输入输出参数,也不能给参数设置默认值 下标可以接受任意数量的入参,并且这些入参可以是任意类型。下标的返回值也可以是任意类型。下标可以使用可变参数,并且可以提供默认参数数值,但不能使用输入输出参数。
一个类或结构体可以根据自身需要提供多个下标实现,使用下标时将通过入参的数量和类型进行区分,自动匹配合适的下标,这就是*下标的重载*。 一个类或结构体可以根据自身需要提供多个下标实现,使用下标时将通过入参的数量和类型进行区分,自动匹配合适的下标,这就是*下标的重载*。
@ -140,3 +140,17 @@ func indexIsValid(row: Int, column: Int) -> Bool {
let someValue = matrix[2, 2] let someValue = matrix[2, 2]
// 断言将会触发,因为 [2, 2] 已经超过了 matrix 的范围 // 断言将会触发,因为 [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)
```

View File

@ -184,7 +184,7 @@ print("Car: \(car.description)")
#### 重写属性观察器 {#overriding-property-observers} #### 重写属性观察器 {#overriding-property-observers}
你可以通过重写属性为一个继承来的属性添加属性观察器。这样一来,无论被继承属性原本是如何实现的,当其属性值发生改变时,你就会被通知到。关于属性观察器的更多内容,请看[属性观察器](../chapter2/10_Properties.html#property_observers)。 你可以通过重写属性为一个继承来的属性添加属性观察器。这样一来,无论被继承属性原本是如何实现的,当其属性值发生改变时,你就会被通知到。关于属性观察器的更多内容,请看 [属性观察器](../chapter2/10_Properties.html#property_observers)。
> 注意 > 注意
> >

View File

@ -4,7 +4,7 @@
你要通过定义*构造器*来实现构造过程,它就像用来创建特定类型新实例的特殊方法。与 Objective-C 中的构造器不同Swift 的构造器没有返回值。它们的主要任务是保证某种类型的新实例在第一次使用前完成正确的初始化。 你要通过定义*构造器*来实现构造过程,它就像用来创建特定类型新实例的特殊方法。与 Objective-C 中的构造器不同Swift 的构造器没有返回值。它们的主要任务是保证某种类型的新实例在第一次使用前完成正确的初始化。
类的实例也可以通过实现*析构器*来执行它释放之前自定义的清理工作。想了解更多关于析构器的内容,请参[析构过程](./15_Deinitialization.md)。 类的实例也可以通过实现*析构器*来执行它释放之前自定义的清理工作。想了解更多关于析构器的内容,请参[析构过程](./15_Deinitialization.md)。
## 存储属性的初始赋值 {#setting-initial-values-for-stored-properties} ## 存储属性的初始赋值 {#setting-initial-values-for-stored-properties}
@ -131,7 +131,7 @@ let veryGreen = Color(0.0, 1.0, 0.0)
如果你不希望构造器的某个形参使用实参标签,可以使用下划线(`_`)来代替显式的实参标签来重写默认行为。 如果你不希望构造器的某个形参使用实参标签,可以使用下划线(`_`)来代替显式的实参标签来重写默认行为。
下面是之前[形参的构造过程](#initialization_parameters)中 `Celsius` 例子的扩展,多了一个用已经的摄氏表示的 `Double` 类型值来创建新的 `Celsius` 实例的额外构造器: 下面是之前 [形参的构造过程](#initialization_parameters) `Celsius` 例子的扩展,多了一个用已经的摄氏表示的 `Double` 类型值来创建新的 `Celsius` 实例的额外构造器:
```swift ```swift
struct Celsius { struct Celsius {
@ -240,11 +240,25 @@ struct Size {
let twoByTwo = Size(width: 2.0, height: 2.0) let twoByTwo = Size(width: 2.0, height: 2.0)
``` ```
当你调用一个逐一成员构造器memberwise initializer可以省略任何一个有默认值的属性。在上面这个例子中`Size` 结构体的 `height``width` 属性各有一个默认值。你可以省略两者或两者之一,对于被省略的属性,构造器会使用默认值。举个例子:
```
let zeroByTwo = Size(height: 2.0)
print(zeroByTwo.width, zeroByTwo.height)
// 打印 "0.0 2.0"
let zeroByZero = Size()
print(zeroByZero.width, zeroByZero.height)
// 打印 "0.0 0.0"
```
## 值类型的构造器代理 {#initializer-delegation-for-value-types} ## 值类型的构造器代理 {#initializer-delegation-for-value-types}
构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为*构造器代理*,它能避免多个构造器间的代码重复。 构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为*构造器代理*,它能避免多个构造器间的代码重复。
构造器代理的实现规则和形式在值类型和类类型中有所不同。值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给自己的其它构造器。类则不同,它可以继承自其它类(请参考[继承](./13_Inheritance.md))。这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。这些责任将在后续章节[类的继承和构造过程](#class_inheritance_and_initialization)中介绍。 构造器代理的实现规则和形式在值类型和类类型中有所不同。值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给自己的其它构造器。类则不同,它可以继承自其它类(请参考 [继承](./13_Inheritance.md))。这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。这些责任将在后续章节 [类的继承和构造过程](#class_inheritance_and_initialization) 中介绍。
对于值类型,你可以使用 `self.init` 在自定义的构造器中引用相同类型中的其它构造器。并且你只能在构造器内部调用 `self.init` 对于值类型,你可以使用 `self.init` 在自定义的构造器中引用相同类型中的其它构造器。并且你只能在构造器内部调用 `self.init`
@ -252,7 +266,7 @@ let twoByTwo = Size(width: 2.0, height: 2.0)
> 注意 > 注意
> >
> 假如你希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展(`extension`)中,而不是写在值类型的原始定义中。想查看更多内容,请查看[扩展](./20_Extensions.md)章节。 > 假如你希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展(`extension`)中,而不是写在值类型的原始定义中。想查看更多内容,请查看 [扩展](./20_Extensions.md) 章节。
下面例子定义一个自定义结构体 `Rect`,用来代表几何矩形。这个例子需要两个辅助的结构体 `Size``Point`,它们各自为其所有的属性提供了默认初始值 `0.0` 下面例子定义一个自定义结构体 `Rect`,用来代表几何矩形。这个例子需要两个辅助的结构体 `Size``Point`,它们各自为其所有的属性提供了默认初始值 `0.0`
@ -314,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:)` 的方式来实现这个例子,请参考 [扩展](./21_Extensions.md)。
## 类的继承和构造过程 {#class-inheritance-and-initialization} ## 类的继承和构造过程 {#class-inheritance-and-initialization}
@ -328,7 +342,7 @@ Swift 为类类型提供了两种构造器来确保实例中所有存储型属
类倾向于拥有极少的指定构造器,普遍的是一个类只拥有一个指定构造器。指定构造器像一个个“漏斗”放在构造过程发生的地方,让构造过程沿着父类链继续往上进行。 类倾向于拥有极少的指定构造器,普遍的是一个类只拥有一个指定构造器。指定构造器像一个个“漏斗”放在构造过程发生的地方,让构造过程沿着父类链继续往上进行。
每一个类都必须至少拥有一个指定构造器。在某些情况下,许多类通过继承了父类中的指定构造器而满足了这个条件。具体内容请参考后续章节[构造器的自动继承](#automatic_initializer_inheritance)。 每一个类都必须至少拥有一个指定构造器。在某些情况下,许多类通过继承了父类中的指定构造器而满足了这个条件。具体内容请参考后续章节 [构造器的自动继承](#automatic_initializer_inheritance)。
*便利构造器*是类中比较次要的、辅助型的构造器。你可以定义便利构造器来调用同一个类中的指定构造器,并为部分形参提供默认值。你也可以定义便利构造器来创建一个特殊用途或特定输入值的实例。 *便利构造器*是类中比较次要的、辅助型的构造器。你可以定义便利构造器来调用同一个类中的指定构造器,并为部分形参提供默认值。你也可以定义便利构造器来创建一个特殊用途或特定输入值的实例。
@ -465,11 +479,11 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
> 注意 > 注意
> >
> 父类的构造器仅会在安全和适当的某些情况下被继承。具体内容请参考后续章节[构造器的自动继承](#automatic_initializer_inheritance)。 > 父类的构造器仅会在安全和适当的某些情况下被继承。具体内容请参考后续章节 [构造器的自动继承](#automatic_initializer_inheritance)。
假如你希望自定义的子类中能提供一个或多个跟父类相同的构造器,你可以在子类中提供这些构造器的自定义实现。 假如你希望自定义的子类中能提供一个或多个跟父类相同的构造器,你可以在子类中提供这些构造器的自定义实现。
当你在编写一个和父类中指定构造器相匹配的子类构造器时,你实际上是在重写父类的这个指定构造器。因此,你必须在定义子类构造器时带上 `override` 修饰符。即使你重写的是系统自动提供的默认构造器,也需要带上 `override` 修饰符,具体内容请参考[默认构造器](#default_initializers)。 当你在编写一个和父类中指定构造器相匹配的子类构造器时,你实际上是在重写父类的这个指定构造器。因此,你必须在定义子类构造器时带上 `override` 修饰符。即使你重写的是系统自动提供的默认构造器,也需要带上 `override` 修饰符,具体内容请参考 [默认构造器](#default_initializers)。
正如重写属性,方法或者是下标,`override` 修饰符会让编译器去检查父类中是否有相匹配的指定构造器,并验证构造器参数是否被按预想中被指定。 正如重写属性,方法或者是下标,`override` 修饰符会让编译器去检查父类中是否有相匹配的指定构造器,并验证构造器参数是否被按预想中被指定。
@ -477,7 +491,7 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
> >
> 当你重写一个父类的指定构造器时,你总是需要写 `override` 修饰符,即使是为了实现子类的便利构造器。 > 当你重写一个父类的指定构造器时,你总是需要写 `override` 修饰符,即使是为了实现子类的便利构造器。
相反,如果你编写了一个和父类便利构造器相匹配的子类构造器,由于子类不能直接调用父类的便利构造器(每个规则都在上文[类的构造器代理规则](#initializer_delegation_for_class_types)有所描述),因此,严格意义上来讲,你的子类并未对一个父类构造器提供重写。最后的结果就是,你在子类中“重写”一个父类便利构造器时,不需要加 `override` 修饰符。 相反,如果你编写了一个和父类便利构造器相匹配的子类构造器,由于子类不能直接调用父类的便利构造器(每个规则都在上文 [类的构造器代理规则](#initializer_delegation_for_class_types) 有所描述),因此,严格意义上来讲,你的子类并未对一个父类构造器提供重写。最后的结果就是,你在子类中“重写”一个父类便利构造器时,不需要加 `override` 修饰符。
在下面的例子中定义了一个叫 `Vehicle` 的基类。基类中声明了一个存储型属性 `numberOfWheels`,它是默认值为 `Int` 类型的 `0``numberOfWheels` 属性用在一个描述车辆特征 `String` 类型为 `descrpiption` 的计算型属性中: 在下面的例子中定义了一个叫 `Vehicle` 的基类。基类中声明了一个存储型属性 `numberOfWheels`,它是默认值为 `Int` 类型的 `0``numberOfWheels` 属性用在一个描述车辆特征 `String` 类型为 `descrpiption` 的计算型属性中:
@ -490,7 +504,7 @@ class Vehicle {
} }
``` ```
`Vehicle` 类只为存储型属性提供默认值,也没有提供自定义构造器。因此,它会自动获得一个默认构造器,具体内容请参考[默认构造器](#default_initializers)。默认构造器(如果有的话)总是类中的指定构造器,可以用于创建 `numberOfWheels``0``Vehicle` 实例: `Vehicle` 类只为存储型属性提供默认值,也没有提供自定义构造器。因此,它会自动获得一个默认构造器,具体内容请参考 [默认构造器](#default_initializers)。默认构造器(如果有的话)总是类中的指定构造器,可以用于创建 `numberOfWheels``0``Vehicle` 实例:
```swift ```swift
let vehicle = Vehicle() let vehicle = Vehicle()
@ -521,7 +535,7 @@ print("Bicycle: \(bicycle.description)")
// 打印“Bicycle: 2 wheel(s)” // 打印“Bicycle: 2 wheel(s)”
``` ```
如果类的构造器没有在阶段 2 过程中做自定义操作,并且父类有一个无参数的自定义构造器你可以在所有类的存储属性赋值之后省略 `super.init()` 的调用。 如果类的构造器没有在阶段 2 过程中做自定义操作,并且父类有一个无参数的指定构造器你可以在所有类的存储属性赋值之后省略 `super.init()` 的调用。
这个例子定义了另一个 `Vehicle` 的子类 `Hoverboard` ,只设置它的 `color` 属性。这个构造器依赖隐式调用父类的构造器来完成,而不是显示调用 `super.init()` 这个例子定义了另一个 `Vehicle` 的子类 `Hoverboard` ,只设置它的 `color` 属性。这个构造器依赖隐式调用父类的构造器来完成,而不是显示调用 `super.init()`
@ -628,11 +642,11 @@ class RecipeIngredient: Food {
![RecipeIngredient 构造器](https://docs.swift.org/swift-book/_images/initializersExample02_2x.png) ![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)`,它只通过 `name` 来创建 `RecipeIngredient` 的实例。这个便利构造器假设任意 `RecipeIngredient` 实例的 `quantity``1`,所以不需要显式的质量即可创建出实例。这个便利构造器的定义可以更加方便和快捷地创建实例,并且避免了创建多个 `quantity``1``RecipeIngredient` 实例时的代码重复。这个便利构造器只是简单地横向代理到类中的指定构造器,并为 `quantity` 参数传递 `1`
`RecipeIngredient` 的便利构造器 `init(name: String)` 使用了跟 `Food` 中指定构造器 `init(name: String)` 相同的形参。由于这个便利构造器重写了父类的指定构造器 `init(name: String)`,因此必须在前面使用 `override` 修饰符(参见[构造器的继承和重写](#initializer_inheritance_and_overriding))。 `RecipeIngredient` 的便利构造器 `init(name: String)` 使用了跟 `Food` 中指定构造器 `init(name: String)` 相同的形参。由于这个便利构造器重写了父类的指定构造器 `init(name: String)`,因此必须在前面使用 `override` 修饰符(参见 [构造器的继承和重写](#initializer_inheritance_and_overriding))。
尽管 `RecipeIngredient` 将父类的指定构造器重写为了便利构造器,但是它依然提供了父类的所有指定构造器的实现。因此,`RecipeIngredient` 会自动继承父类的所有便利构造器。 尽管 `RecipeIngredient` 将父类的指定构造器重写为了便利构造器,但是它依然提供了父类的所有指定构造器的实现。因此,`RecipeIngredient` 会自动继承父类的所有便利构造器。

View File

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

View File

@ -156,7 +156,7 @@ class Address {
## 通过可选链式调用访问属性 {#accessing-properties-through-optional-chaining} ## 通过可选链式调用访问属性 {#accessing-properties-through-optional-chaining}
正如[使用可选链式调用代替强制展开](#optional_chaining_as_an_alternative_to_forced_unwrapping)中所述,可以通过可选链式调用在一个可选值上访问它的属性,并判断访问是否成功。 正如 [使用可选链式调用代替强制展开](#optional_chaining_as_an_alternative_to_forced_unwrapping) 中所述,可以通过可选链式调用在一个可选值上访问它的属性,并判断访问是否成功。
使用前面定义过的类,创建一个 `Person` 实例,然后像之前一样,尝试访问 `numberOfRooms` 属性: 使用前面定义过的类,创建一个 `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` 可以判断调用是否成功: 如果在可选值上通过可选链式调用来调用这个方法,该方法的返回类型会是 `Void?`,而不是 `Void`,因为通过可选链式调用得到的返回值都是可选的。这样我们就可以使用 `if` 语句来判断能否成功调用 `printNumberOfRooms()` 方法,即使方法本身没有定义返回值。通过判断返回值是否为 `nil` 可以判断调用是否成功:
@ -225,7 +225,7 @@ if john.residence?.printNumberOfRooms() != nil {
// 打印“It was not possible to print the number of rooms.” // 打印“It was not possible to print the number of rooms.”
``` ```
同样的,可以据此判断通过可选链式调用为属性赋值是否成功。在上面的[通过可选链式调用访问属性](#accessing_properties_through_optional_chaining)的例子中,我们尝试给 `john.residence` 中的 `address` 属性赋值,即使 `residence``nil`。通过可选链式调用给属性赋值会返回 `Void?`,通过判断返回值是否为 `nil` 就可以知道赋值是否成功: 同样的,可以据此判断通过可选链式调用为属性赋值是否成功。在上面的 [通过可选链式调用访问属性](#accessing_properties_through_optional_chaining) 的例子中,我们尝试给 `john.residence` 中的 `address` 属性赋值,即使 `residence``nil`。通过可选链式调用给属性赋值会返回 `Void?`,通过判断返回值是否为 `nil` 就可以知道赋值是否成功:
```swift ```swift
if (john.residence?.address = someAddress) != nil { if (john.residence?.address = someAddress) != nil {

View File

@ -114,7 +114,7 @@ func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
} }
``` ```
上例中,`buyFavoriteSnack(person:vendingMachine:)` 函数会查找某人最喜欢的零食,并通过调用 `vend(itemNamed:)` 方法来尝试为他们购买。因为 `vend(itemNamed:)` 方法能抛出错误,所以在调用它时候在它前面加了 `try` 关键字。 上例中,`buyFavoriteSnack(person:vendingMachine:)` 函数会查找某人最喜欢的零食,并通过调用 `vend(itemNamed:)` 方法来尝试为他们购买。因为 `vend(itemNamed:)` 方法能抛出错误,所以在调用它时候在它前面加了 `try` 关键字。
`throwing` 构造器能像 `throwing` 函数一样传递错误。例如下面代码中的 `PurchasedSnack` 构造器在构造过程中调用了 throwing 函数,并且通过传递到它的调用者来处理这些错误。 `throwing` 构造器能像 `throwing` 函数一样传递错误。例如下面代码中的 `PurchasedSnack` 构造器在构造过程中调用了 throwing 函数,并且通过传递到它的调用者来处理这些错误。

View File

@ -4,7 +4,7 @@
类型转换在 Swift 中使用 `is``as` 操作符实现。这两个操作符分别提供了一种简单达意的方式去检查值的类型或者转换它的类型。 类型转换在 Swift 中使用 `is``as` 操作符实现。这两个操作符分别提供了一种简单达意的方式去检查值的类型或者转换它的类型。
你也可以用它来检查一个类型是否遵循了某个协议,就像在[检验协议遵循](./21_Protocols.md#checking_for_protocol_conformance)部分讲述的一样。 你也可以用它来检查一个类型是否遵循了某个协议,就像在 [检验协议遵循](./21_Protocols.md#checking_for_protocol_conformance) 部分讲述的一样。
## 为类型转换定义类层次 {#defining-a-class-hierarchy-for-type-casting} ## 为类型转换定义类层次 {#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` 结构体拥有两个属性——`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 ```swift
let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades) let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)

View File

@ -95,7 +95,7 @@ var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// ncc1701.fullName 为 "USS Enterprise" // ncc1701.fullName 为 "USS Enterprise"
``` ```
`Starship`只能`fullName` 作为只读的计算属性来实现。每一个 `Starship` 类的实例都有一个名为 `name` 的非可选属性和一个名为 `prefix` 的可选属性。 当 `prefix` 存在时,计算属性 `fullName` 会将 `prefix` 插入到 `name` 之前,从而得到一个带有 `prefix``fullName` `Starship` 类把 `fullName` 作为只读的计算属性来实现。每一个 `Starship` 类的实例都有一个名为 `name` 的非可选属性和一个名为 `prefix` 的可选属性。 当 `prefix` 存在时,计算属性 `fullName` 会将 `prefix` 插入到 `name` 之前,从而得到一个带有 `prefix``fullName`
## 方法要求 {#method-requirements} ## 方法要求 {#method-requirements}
@ -242,7 +242,7 @@ class SomeSubClass: SomeSuperClass, SomeProtocol {
## 协议作为类型 {#protocols-as-types} ## 协议作为类型 {#protocols-as-types}
尽管协议本身并未实现任何功能,但是协议可以被当做一个功能完备的类型来使用。 尽管协议本身并未实现任何功能,但是协议可以被当做一个功能完备的类型来使用。协议作为类型使用,有时被称作「存在类型」,这个名词来自「存在着一个类型 T该类型遵循协议 T」。
协议可以像其他普通类型一样使用,使用场景如下: 协议可以像其他普通类型一样使用,使用场景如下:
@ -272,7 +272,7 @@ class Dice {
例子中定义了一个 `Dice` 类,用来代表桌游中拥有 N 个面的骰子。`Dice` 的实例含有 `sides``generator` 两个属性,前者是整型,用来表示骰子有几个面,后者为骰子提供一个随机数生成器,从而生成随机点数。 例子中定义了一个 `Dice` 类,用来代表桌游中拥有 N 个面的骰子。`Dice` 的实例含有 `sides``generator` 两个属性,前者是整型,用来表示骰子有几个面,后者为骰子提供一个随机数生成器,从而生成随机点数。
`generator` 属性的类型为 `RandomNumberGenerator`,因此任何遵循了 `RandomNumberGenerator` 协议的类型的实例都可以赋值给 `generator`,除此之外并无其他要求。 `generator` 属性的类型为 `RandomNumberGenerator`,因此任何遵循了 `RandomNumberGenerator` 协议的类型的实例都可以赋值给 `generator`,除此之外并无其他要求。并且由于其类型是 `RandomNumberGenerator`,在 `Dice` 类中与 `generator` 交互的代码,必须适用于所有 `generator` 实例都遵循的方法。这句话的意思是不能使用由 `generator` 底层类型提供的任何方法或属性。但是你可以通过向下转型,从协议类型转换成底层实现类型,比如从父类向下转型为子类。请参考 [向下转型](./18_Type_Casting#downcasting)。
`Dice` 类还有一个构造器,用来设置初始状态。构造器有一个名为 `generator`,类型为 `RandomNumberGenerator` 的形参。在调用构造方法创建 `Dice` 的实例时,可以传入任何遵循 `RandomNumberGenerator` 协议的实例给 `generator` `Dice` 类还有一个构造器,用来设置初始状态。构造器有一个名为 `generator`,类型为 `RandomNumberGenerator` 的形参。在调用构造方法创建 `Dice` 的实例时,可以传入任何遵循 `RandomNumberGenerator` 协议的实例给 `generator`
@ -656,7 +656,7 @@ beginConcert(in: seattle)
## 检查协议一致性 {#checking-for-protocol-conformance} ## 检查协议一致性 {#checking-for-protocol-conformance}
你可以使用[类型转换](./18_Type_Casting.md)中描述的 `is``as` 操作符来检查协议一致性,即是否符合某协议,并且可以转换到指定的协议类型。检查和转换协议的语法与检查和转换类型是完全一样的: 你可以使用 [类型转换](./18_Type_Casting.md) 中描述的 `is``as` 操作符来检查协议一致性,即是否符合某协议,并且可以转换到指定的协议类型。检查和转换协议的语法与检查和转换类型是完全一样的:
* `is` 用来检查实例是否符合某个协议,若符合则返回 `true`,否则返回 `false` * `is` 用来检查实例是否符合某个协议,若符合则返回 `true`,否则返回 `false`
* `as?` 返回一个可选值,当实例符合某个协议时,返回类型为协议类型的可选值,否则返回 `nil` * `as?` 返回一个可选值,当实例符合某个协议时,返回类型为协议类型的可选值,否则返回 `nil`
@ -733,7 +733,7 @@ for object in objects {
使用可选要求时(例如,可选的方法或者属性),它们的类型会自动变成可选的。比如,一个类型为 `(Int) -> String` 的方法会变成 `((Int) -> String)?`。需要注意的是整个函数类型是可选的,而不是函数的返回值。 使用可选要求时(例如,可选的方法或者属性),它们的类型会自动变成可选的。比如,一个类型为 `(Int) -> String` 的方法会变成 `((Int) -> String)?`。需要注意的是整个函数类型是可选的,而不是函数的返回值。
协议中的可选要求可通过可选链式调用来使用,因为遵循协议的类型可能没有实现这些可选要求。类似 `someOptionalMethod?(someArgument)` 这样,你可以在可选方法名称后加上 `?` 来调用可选方法。详细内容可在[可选链式调用](./16_Optional_Chaining.md)章节中查看。 协议中的可选要求可通过可选链式调用来使用,因为遵循协议的类型可能没有实现这些可选要求。类似 `someOptionalMethod?(someArgument)` 这样,你可以在可选方法名称后加上 `?` 来调用可选方法。详细内容可在 [可选链式调用](./16_Optional_Chaining.md) 章节中查看。
下面的例子定义了一个名为 `Counter` 的用于整数计数的类,它使用外部的数据源来提供每次的增量。数据源由 `CounterDataSource` 协议定义,它包含两个可选要求: 下面的例子定义了一个名为 `Counter` 的用于整数计数的类,它使用外部的数据源来提供每次的增量。数据源由 `CounterDataSource` 协议定义,它包含两个可选要求:
@ -772,7 +772,7 @@ class Counter {
这里使用了两层可选链式调用。首先,由于 `dataSource` 可能为 `nil`,因此在 `dataSource` 后边加上了 `?`,以此表明只在 `dataSource` 非空时才去调用 `increment(forCount:)` 方法。其次,即使 `dataSource` 存在,也无法保证其是否实现了 `increment(forCount:)` 方法,因为这个方法是可选的。因此,`increment(forCount:)` 方法同样使用可选链式调用进行调用,只有在该方法被实现的情况下才能调用它,所以在 `increment(forCount:)` 方法后边也加上了 `?` 这里使用了两层可选链式调用。首先,由于 `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)
在调用 `increment(forCount:)` 方法后,`Int?` 型的返回值通过可选绑定解包并赋值给常量 `amount`。如果可选值确实包含一个数值,也就是说,数据源和方法都存在,数据源方法返回了一个有效值。之后便将解包后的 `amount` 加到 `count` 上,增量操作完成。 在调用 `increment(forCount:)` 方法后,`Int?` 型的返回值通过可选绑定解包并赋值给常量 `amount`。如果可选值确实包含一个数值,也就是说,数据源和方法都存在,数据源方法返回了一个有效值。之后便将解包后的 `amount` 加到 `count` 上,增量操作完成。
@ -881,7 +881,7 @@ extension PrettyTextRepresentable {
### 为协议扩展添加限制条件 {#adding-constraints-to-protocol-extensions} ### 为协议扩展添加限制条件 {#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` 协议, 作为标准库的一部分, 你可以使用 `==``!=` 操作符来检查两个元素的等价性和非等价性。

View File

@ -1,6 +1,6 @@
# 泛型 # 泛型
*泛型代码*让你能根据自定义的需求,编写出适用于任意类型的、灵活可复用的函数及类型。你可避免编写重复的代码,用一种清晰抽象的方式来表达代码的意图。 *泛型代码*让你能根据自定义的需求,编写出适用于任意类型的、灵活可复用的函数及类型。你可避免编写重复的代码,而是用一种清晰抽象的方式来表达代码的意图。
泛型是 Swift 最强大的特性之一,很多 Swift 标准库是基于泛型代码构建的。实际上,即使你没有意识到,你也一直在*语言指南*中使用泛型。例如Swift 的 `Array``Dictionary` 都是泛型集合。你可以创建一个 `Int` 类型数组,也可创建一个 `String` 类型数组,甚至可以是任意其他 Swift 类型的数组。同样,你也可以创建一个存储任意指定类型的字典,并对该类型没有限制。 泛型是 Swift 最强大的特性之一,很多 Swift 标准库是基于泛型代码构建的。实际上,即使你没有意识到,你也一直在*语言指南*中使用泛型。例如Swift 的 `Array``Dictionary` 都是泛型集合。你可以创建一个 `Int` 类型数组,也可创建一个 `String` 类型数组,甚至可以是任意其他 Swift 类型的数组。同样,你也可以创建一个存储任意指定类型的字典,并对该类型没有限制。
@ -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` 类型变量: `swapTwoInts(_:_:)` 函数将 `b` 的原始值换成了 `a`,将 `a` 的原始值换成了 `b`,你可以调用这个函数来交换两个 `Int` 类型变量:
@ -226,6 +226,8 @@ if let topItem = stackOfStrings.topItem {
// 打印“The top item on the stack is tres.” // 打印“The top item on the stack is tres.”
``` ```
泛型类型的扩展,还可以包括类型扩展需要额外满足的条件,从而对类型添加新功能,这一部分将在[具有泛型 Where 子句的扩展](#extensions-with-a-generic-where-clause)中进行讨论。
## 类型约束 {#type-constraints} ## 类型约束 {#type-constraints}
`swapTwoValues(_:_:)` 函数和 `Stack` 适用于任意类型。不过,如果能对泛型函数或泛型类型中添加特定的*类型约束*,这将在某些情况下非常有用。类型约束指定类型参数必须继承自指定类、遵循特定的协议或协议组合。 `swapTwoValues(_:_:)` 函数和 `Stack` 适用于任意类型。不过,如果能对泛型函数或泛型类型中添加特定的*类型约束*,这将在某些情况下非常有用。类型约束指定类型参数必须继承自指定类、遵循特定的协议或协议组合。
@ -408,7 +410,7 @@ struct Stack<Element>: Container {
### 扩展现有类型来指定关联类型 {#extending-an-existing-type-to-specify-an-associated-type} ### 扩展现有类型来指定关联类型 {#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 协议。你可以通过一个空扩展来实现这点,正如通过扩展采纳协议中的描述: Swift 的 `Array` 类型已经提供 `append(_:)` 方法,`count` 属性,以及带有 `Int` 索引的下标来检索其元素。这三个功能都符合 `Container` 协议的要求,也就意味着你只需声明 `Array` 遵循`Container` 协议,就可以扩展 Array使其遵从 Container 协议。你可以通过一个空扩展来实现这点,正如通过扩展采纳协议中的描述:
@ -433,7 +435,7 @@ protocol Container {
要遵守 `Container` 协议,`Item` 类型也必须遵守 `Equatable` 协议。 要遵守 `Container` 协议,`Item` 类型也必须遵守 `Equatable` 协议。
### 在关联类型约束里使用协议 {#using-a-protocol-in-its-associated-types-constraints} ### 在关联类型约束里使用协议 {#using-a-protocol-in-its-associated-types-constraints}
协议可以作为它自身的要求出现。例如,有一个协议细化了 `Container` 协议,添加了一个` suffix(_:)` 方法。`suffix(_:)` 方法返回容器中从后往前给定数量的元素,并把它们存储在一个 `Suffix` 类型的实例里。 协议可以作为它自身的要求出现。例如,有一个协议细化了 `Container` 协议,添加了一个` suffix(_:)` 方法。`suffix(_:)` 方法返回容器中从后往前给定数量的元素,并把它们存储在一个 `Suffix` 类型的实例里。
@ -444,9 +446,9 @@ protocol SuffixableContainer: Container {
} }
``` ```
在这个协议里,`Suffix` 是一个关联类型,就像上边例子中 `Container``Item` 类型一样。`Suffix` 拥有两个约束:它必须遵循 `SuffixableContainer` 协议(就是当前定义的协议),以及它的 `Item` 类型必须是和容器里的 `Item` 类型相同。`Item` 的约束是一个 `where` 分句,它在下面有泛型 `Where` 分句的扩展中有讨论。 在这个协议里,`Suffix` 是一个关联类型,就像上边例子中 `Container``Item` 类型一样。`Suffix` 拥有两个约束:它必须遵循 `SuffixableContainer` 协议(就是当前定义的协议),以及它的 `Item` 类型必须是和容器里的 `Item` 类型相同。`Item` 的约束是一个 `where` 分句,它在下面[有泛型 Where 子句的扩展](#extensions-with-a-generic-where-clause)中有讨论。
这是上面 [强引用循环闭包](./23_Automatic_Reference_Counting.md#strong_reference_cycles_for_closures) 中 `Stack` 类型的扩展,它遵循了 SuffixableContainer 协议: 这是上面 [泛型类型](#generic-types) 中 `Stack` 类型的扩展,它遵循了 SuffixableContainer 协议:
```swift ```swift
extension Stack: SuffixableContainer { extension Stack: SuffixableContainer {
@ -484,7 +486,7 @@ extension IntStack: SuffixableContainer {
## 泛型 Where 语句 {#where-clauses} ## 泛型 Where 语句 {#where-clauses}
[类型约束](#type_constraints)让你能够为泛型函数、下标、类型的类型参数定义一些强制要求。 [类型约束](#type_constraints) 让你能够为泛型函数、下标、类型的类型参数定义一些强制要求。
对关联类型添加约束通常是非常有用的。你可以通过定义一个泛型 `where` 子句来实现。通过泛型 `where` 子句让关联类型遵从某个特定的协议,以及某个特定的类型参数和关联类型必须类型相同。你可以通过将 `where` 关键字紧跟在类型参数列表后面来定义 `where` 子句,`where` 子句后跟一个或者多个针对关联类型的约束,以及一个或多个类型参数和关联类型间的相等关系。你可以在函数体或者类型的大括号之前添加 `where` 子句。 对关联类型添加约束通常是非常有用的。你可以通过定义一个泛型 `where` 子句来实现。通过泛型 `where` 子句让关联类型遵从某个特定的协议,以及某个特定的类型参数和关联类型必须类型相同。你可以通过将 `where` 关键字紧跟在类型参数列表后面来定义 `where` 子句,`where` 子句后跟一个或者多个针对关联类型的约束,以及一个或多个类型参数和关联类型间的相等关系。你可以在函数体或者类型的大括号之前添加 `where` 子句。

View File

@ -2,7 +2,7 @@
Swift 使用*自动引用计数ARC*机制来跟踪和管理你的应用程序的内存。通常情况下Swift 内存管理机制会一直起作用你无须自己来考虑内存的管理。ARC 会在类的实例不再被使用时,自动释放其占用的内存。 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)
> 注意 > 注意
> >
@ -87,7 +87,7 @@ reference3 = nil
然而,我们可能会写出一个类实例的强引用数*永远不能*变成 `0` 的代码。如果两个类实例互相持有对方的强引用,因而每个实例都让对方一直存在,就是这种情况。这就是所谓的*循环强引用*。 然而,我们可能会写出一个类实例的强引用数*永远不能*变成 `0` 的代码。如果两个类实例互相持有对方的强引用,因而每个实例都让对方一直存在,就是这种情况。这就是所谓的*循环强引用*。
你可以通过定义类之间的关系为弱引用或无主引用,以替代强引用,从而解决循环强引用的问题。具体的过程在[解决类实例之间的循环强引用](#resolving_strong_reference_cycles_between_class_instances)中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是怎样产生的。 你可以通过定义类之间的关系为弱引用或无主引用,以替代强引用,从而解决循环强引用的问题。具体的过程在 [解决类实例之间的循环强引用](#resolving_strong_reference_cycles_between_class_instances) 中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是怎样产生的。
下面展示了一个不经意产生循环强引用的例子。例子定义了两个类:`Person``Apartment`,用来建模公寓和它其中的居民: 下面展示了一个不经意产生循环强引用的例子。例子定义了两个类:`Person``Apartment`,用来建模公寓和它其中的居民:
@ -357,9 +357,9 @@ class City {
为了建立两个类的依赖关系,`City` 的构造器接受一个 `Country` 实例作为参数,并且将实例保存到 `country` 属性。 为了建立两个类的依赖关系,`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` 的构造器。 由于 `capitalCity` 默认值为 `nil`,一旦 `Country` 的实例在构造器中给 `name` 属性赋值后,整个初始化过程就完成了。这意味着一旦 `name` 属性被赋值后,`Country` 的构造器就能引用并传递隐式的 `self``Country` 的构造器在赋值 `capitalCity` 时,就能将 `self` 作为参数传递给 `City` 的构造器。
@ -453,7 +453,7 @@ print(paragraph!.asHTML())
![](https://docs.swift.org/swift-book/_images/closureReferenceCycle01_2x.png) ![](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))。
> 注意 > 注意
> >
@ -557,4 +557,4 @@ paragraph = nil
// 打印“p is being deinitialized” // 打印“p is being deinitialized”
``` ```
你可以查看[捕获列表](../chapter3/04_Expressions.html)章节,获取更多关于捕获列表的信息。 你可以查看 [捕获列表](../chapter3/04_Expressions.html) 章节,获取更多关于捕获列表的信息。

View File

@ -42,7 +42,7 @@ Open 只能作用于类和类的成员,它和 Public 的区别如下:
### 访问级别基本原则 {#guiding-principle-of-access-levels} ### 访问级别基本原则 {#guiding-principle-of-access-levels}
Swift 中的访问级别遵循一个基本原则:*不可以在某个实体中定义访问级别更低(更严格)的实体*。 Swift 中的访问级别遵循一个基本原则:*实体不能定义在具有更低访问级别(更严格)的实体*。
例如: 例如:
@ -65,7 +65,7 @@ Swift 中的访问级别遵循一个基本原则:*不可以在某个实体中
> 注意 > 注意
> >
> 框架依然会使用默认的 `internal` ,也可以指定为 `fileprivate` 访问或者 `private` 访问级别。当你想把某个实体作为框架的 API 的时候,需显式为其指定开放访问或公开访问级别 > 框架的内部实现仍然可以使用默认的访问级别 `internal`,当你需要对框架内部其它部分隐藏细节时可以使用 `private` 或 `fileprivate`。对于框架的对外 API 部分,你就需要将它们设置为 `open` 或 `public` 了
### 单元测试 target 的访问级别 {#access-levels-for-unit-test-targets} ### 单元测试 target 的访问级别 {#access-levels-for-unit-test-targets}
@ -87,7 +87,7 @@ fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {} private func somePrivateFunction() {}
``` ```
除非专门指定,否则实体默认的访问级别为 `internal`,可以查阅[默认访问级别](#default_access_levels)这一节。这意味着在不使用修饰符显式声明访问级别的情况下,`SomeInternalClass``someInternalConstant` 仍然拥有隐式的 `internal` 除非专门指定,否则实体默认的访问级别为 `internal`,可以查阅 [默认访问级别](#default_access_levels) 这一节。这意味着在不使用修饰符显式声明访问级别的情况下,`SomeInternalClass``someInternalConstant` 仍然拥有隐式的 `internal`
```swift ```swift
class SomeInternalClass {} // 隐式 internal class SomeInternalClass {} // 隐式 internal
@ -98,7 +98,7 @@ var someInternalConstant = 0 // 隐式 internal
如果想为一个自定义类型指定访问级别,在定义类型时进行指定即可。新类型只能在它的访问级别限制范围内使用。例如,你定义了一个 `fileprivate` 级别的类,那这个类就只能在定义它的源文件中使用,可以作为属性类型、函数参数类型或者返回类型,等等。 如果想为一个自定义类型指定访问级别,在定义类型时进行指定即可。新类型只能在它的访问级别限制范围内使用。例如,你定义了一个 `fileprivate` 级别的类,那这个类就只能在定义它的源文件中使用,可以作为属性类型、函数参数类型或者返回类型,等等。
一个类型的访问级别也会影响到类型*成员*(属性、方法、构造器、下标)的默认访问级别。如果你将类型指定为 `private` 或者 `fileprivate` 级别,那么该类型的所有成员的默认访问级别也会变成 `private` 或者 `fileprivate` 级别。如果你将类型指定为公开或者 `internal` (或者不明确指定访问级别,而使用默认的 `internal` ),那么该类型的所有成员的默认访问级别将是内部访问 一个类型的访问级别也会影响到类型*成员*(属性、方法、构造器、下标)的默认访问级别。如果你将类型指定为 `private` 或者 `fileprivate` 级别,那么该类型的所有成员的默认访问级别也会变成 `private` 或者 `fileprivate` 级别。如果你将类型指定为 `internal` `public`(或者不明确指定访问级别,而使用默认的 `internal` ),那么该类型的所有成员的默认访问级别将是 `internal`
> 重点 > 重点
> >
@ -147,7 +147,7 @@ func someFunction() -> (SomeInternalClass, SomePrivateClass) {
} }
``` ```
我们可以看到,这个函数的返回类型是一个元组,该元组中包含两个自定义的类(可查阅[自定义类型](#custom_types))。其中一个类的访问级别是 `internal`,另一个的访问级别是 `private`,所以根据元组访问级别的原则,该元组的访问级别是 `private`(元组的访问级别与元组中访问级别最低的类型一致)。 我们可以看到,这个函数的返回类型是一个元组,该元组中包含两个自定义的类(可查阅 [自定义类型](#custom_types))。其中一个类的访问级别是 `internal`,另一个的访问级别是 `private`,所以根据元组访问级别的原则,该元组的访问级别是 `private`(元组的访问级别与元组中访问级别最低的类型一致)。
因为该函数返回类型的访问级别是 `private`,所以你必须使用 `private` 修饰符,明确指定该函数的访问级别: 因为该函数返回类型的访问级别是 `private`,所以你必须使用 `private` 修饰符,明确指定该函数的访问级别:
@ -188,7 +188,7 @@ public enum CompassPoint {
此外,你可以在符合当前访问级别的条件下重写任意类成员(方法、属性、构造器、下标等)。 此外,你可以在符合当前访问级别的条件下重写任意类成员(方法、属性、构造器、下标等)。
可以通过重写为继承来的类成员提供更高的访问级别。下面的例子中,类 `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 ```swift
public class A { public class A {
@ -200,7 +200,7 @@ internal class B: A {
} }
``` ```
我们甚至可以在子类中,用子类成员去访问访问级别更低的父类成员,只要这一操作在相应访问级别的限制范围内(也就是说,在同一源文件中访问父类 `private` 级别的成员,在同一模块内访问父类 `internal` 级别的成员): 我们甚至可以在子类中,用子类成员去访问访问级别更低的父类成员,只要这一操作在相应访问级别的限制范围内(也就是说,在同一源文件中访问父类 `fileprivate` 级别的成员,在同一模块内访问父类 `internal` 级别的成员):
```swift ```swift
public class A { public class A {
@ -282,13 +282,13 @@ public struct TrackedString {
## 构造器 {#initializers} ## 构造器 {#initializers}
自定义构造器的访问级别可以低于或等于其所属类型的访问级别。唯一的例外是[必要构造器](./14_Initialization.md#required_initializers),它的访问级别必须和所属类型的访问级别相同。 自定义构造器的访问级别可以低于或等于其所属类型的访问级别。唯一的例外是 [必要构造器](./14_Initialization.md#required_initializers),它的访问级别必须和所属类型的访问级别相同。
如同函数或方法的参数,构造器参数的访问级别也不能低于构造器本身的访问级别。 如同函数或方法的参数,构造器参数的访问级别也不能低于构造器本身的访问级别。
### 默认构造器 {#default-initializers} ### 默认构造器 {#default-initializers}
如[默认构造器](./14_Initialization.md#default_initializers)所述Swift 会为结构体和类提供一个默认的无参数的构造器,只要它们为所有存储型属性设置了默认初始值,并且未提供自定义的构造器。 [默认构造器](./14_Initialization.md#default_initializers) 所述Swift 会为结构体和类提供一个默认的无参数的构造器,只要它们为所有存储型属性设置了默认初始值,并且未提供自定义的构造器。
默认构造器的访问级别与所属类型的访问级别相同,除非类型的访问级别是 `public`。如果一个类型被指定为 `public` 级别,那么默认构造器的访问级别将为 `internal`。如果你希望一个 `public` 级别的类型也能在其他模块中使用这种无参数的默认构造器,你只能自己提供一个 `public` 访问级别的无参数构造器。 默认构造器的访问级别与所属类型的访问级别相同,除非类型的访问级别是 `public`。如果一个类型被指定为 `public` 级别,那么默认构造器的访问级别将为 `internal`。如果你希望一个 `public` 级别的类型也能在其他模块中使用这种无参数的默认构造器,你只能自己提供一个 `public` 访问级别的无参数构造器。

View File

@ -1,6 +1,6 @@
# 高级运算符 # 高级运算符
除了之前介绍过的[基本运算符](./02_Basic_Operators.md)Swift 还提供了数种可以对数值进行复杂运算的高级运算符。它们包含了在 C 和 Objective-C 中已经被大家所熟知的位运算符和移位运算符。 除了之前介绍过的 [基本运算符](./02_Basic_Operators.md)Swift 还提供了数种可以对数值进行复杂运算的高级运算符。它们包含了在 C 和 Objective-C 中已经被大家所熟知的位运算符和移位运算符。
与 C 语言中的算术运算符不同Swift 中的算术运算符默认是不会溢出的。所有溢出行为都会被捕获并报告为错误。如果想让系统允许溢出行为,可以选择使用 Swift 中另一套默认支持溢出的运算符,比如溢出加法运算符(`&+`)。所有的这些溢出运算符都是以 `&` 开头的。 与 C 语言中的算术运算符不同Swift 中的算术运算符默认是不会溢出的。所有溢出行为都会被捕获并报告为错误。如果想让系统允许溢出行为,可以选择使用 Swift 中另一套默认支持溢出的运算符,比如溢出加法运算符(`&+`)。所有的这些溢出运算符都是以 `&` 开头的。
@ -210,7 +210,7 @@ unsignedOverflow = unsignedOverflow &- 1
![Art/overflowUnsignedSubtraction_2x.png](https://docs.swift.org/swift-book/_images/overflowUnsignedSubtraction_2x.png) ![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 ```Swift
var signedOverflow = Int8.min var signedOverflow = Int8.min
@ -266,7 +266,7 @@ signedOverflow = signedOverflow &- 1
因此计算结果为 `17` 因此计算结果为 `17`
有关 Swift 标准库提供的操作符信息,包括操作符优先级组和结核性设置的完整列表,请参见[操作符声明](https://developer.apple.com/documentation/swift/operator_declarations)。 有关 Swift 标准库提供的操作符信息,包括操作符优先级组和结核性设置的完整列表,请参见 [操作符声明](https://developer.apple.com/documentation/swift/operator_declarations)。
> 注意 > 注意
> >
@ -414,7 +414,7 @@ if twoThreeFour == anotherTwoThreeFour {
## 自定义运算符 {#custom-operators} ## 自定义运算符 {#custom-operators}
除了实现标准运算符,在 Swift 中还可以声明和实现*自定义运算符*。可以用来自定义运算符的字符列表请参考[运算符](../chapter3/02_Lexical_Structure.html#operators)。 除了实现标准运算符,在 Swift 中还可以声明和实现*自定义运算符*。可以用来自定义运算符的字符列表请参考 [运算符](../chapter3/02_Lexical_Structure.html#operators)。
新的运算符要使用 `operator` 关键字在全局作用域内进行定义,同时还要指定 `prefix``infix` 或者 `postfix` 修饰符: 新的运算符要使用 `operator` 关键字在全局作用域内进行定义,同时还要指定 `prefix``infix` 或者 `postfix` 修饰符:
@ -440,7 +440,7 @@ let afterDoubling = +++toBeDoubled
### 自定义中缀运算符的优先级 {#precedence-and-associativity-for-custom-infix-operators} ### 自定义中缀运算符的优先级 {#precedence-and-associativity-for-custom-infix-operators}
每个自定义中缀运算符都属于某个优先级组。优先级组指定了这个运算符相对于其他中缀运算符的优先级和结合性。[优先级和结合性](#precedence_and_associativity)中详细阐述了这两个特性是如何对中缀运算符的运算产生影响的。 每个自定义中缀运算符都属于某个优先级组。优先级组指定了这个运算符相对于其他中缀运算符的优先级和结合性。[优先级和结合性](#precedence_and_associativity) 中详细阐述了这两个特性是如何对中缀运算符的运算产生影响的。
而没有明确放入某个优先级组的自定义中缀运算符将会被放到一个默认的优先级组内,其优先级高于三元运算符。 而没有明确放入某个优先级组的自定义中缀运算符将会被放到一个默认的优先级组内,其优先级高于三元运算符。
@ -459,7 +459,7 @@ let plusMinusVector = firstVector +- secondVector
// plusMinusVector 是一个 Vector2D 实例,并且它的值为 (4.0, -2.0) // 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)。而更多关于优先级组以及自定义操作符和优先级组的语法,请参考 [运算符声明](./06_Declarations.md#operator_declaration)。
> 注意 > 注意
> >

View File

@ -0,0 +1,249 @@
# 不透明类型
具有不透明返回类型的函数或方法会隐藏返回值的类型信息。函数不再提供具体的类型作为返回类型,而是根据它支持的协议来描述返回值。在处理模块和调用代码之间的关系时,隐藏类型信息非常有用,因为返回的底层数据类型仍然可以保持私有。而且不同于返回协议类型,不透明类型能保证类型一致性 —— 编译器能获取到类型信息,同时模块使用者却不能获取到。
## 不透明类型解决的问题 {#the-problem-that-opaque-types-solve}
举个例子,假设你正在写一个模块,用来绘制 ASCII 符号构成的几何图形。它的基本特征是有一个 `draw()` 方法,会返回一个代表最终几何图形的字符串,你可以用包含这个方法的 `Shape` 协议来描述:
```swift
protocol Shape {
func draw() -> String
}
struct Triangle: Shape {
var size: Int
func draw() -> String {
var result = [String]()
for length in 1...size {
result.append(String(repeating: "*", count: length))
}
return result.joined(separator: "\n")
}
}
let smallTriangle = Triangle(size: 3)
print(smallTriangle.draw())
// *
// **
// ***
```
你可以利用泛型来实现垂直翻转之类的操作,就像下面这样。然而,这种方式有一个很大的局限:翻转操作的结果会暴露我们用于构造结果的泛型类型:
```swift
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {
let lines = shape.draw().split(separator: "\n")
return lines.reversed().joined(separator: "\n")
}
}
let flippedTriangle = FlippedShape(shape: smallTriangle)
print(flippedTriangle.draw())
// ***
// **
// *
```
如下方代码所示,用同样的方式定义了一个 `JoinedShape<T: Shape, U: Shape>` 结构体,能将几何图形垂直拼接起来。如果拼接一个翻转三角形和一个普通三角形,它就会得到类似于 `JoinedShape<FlippedShape<Triangle>, Triangle>` 这样的类型。
```swift
struct JoinedShape<T: Shape, U: Shape>: Shape {
var top: T
var bottom: U
func draw() -> String {
return top.draw() + "\n" + bottom.draw()
}
}
let joinedTriangles = JoinedShape(top: smallTriangle, bottom: flippedTriangle)
print(joinedTriangles.draw())
// *
// **
// ***
// ***
// **
// *
```
暴露构造所用的具体类型会造成类型信息的泄露,因为 ASCII 几何图形模块的部分公开接口必须声明完整的返回类型,而实际上这些类型信息并不应该被公开声明。输出同一种几何图形,模块内部可能有多种实现方式,而外部使用时,应该与内部各种变换顺序的实现逻辑无关。诸如 `JoinedShape``FlippedShape` 这样包装后的类型,模块使用者并不关心,它们也不应该可见。模块的公开接口应该由拼接、翻转等基础操作组成,这些操作也应该返回独立的 `Shape` 类型的值。
## 返回不透明类型 {#returning-an-opaque-type}
你可以认为不透明类型和泛型相反。泛型允许调用一个方法时,为这个方法的形参和返回值指定一个与实现无关的类型。举个例子,下面这个函数的返回值类型就由它的调用者决定:
```swift
func max<T>(_ x: T, _ y: T) -> T where T: Comparable { ... }
```
`x``y` 的值由调用 `max(_:_:)` 的代码决定,而它们的类型决定了 `T` 的具体类型。调用代码可以使用任何遵循了 `Comparable` 协议的类型,函数内部也要以一种通用的方式来写代码,才能应对调用者传入的各种类型。`max(_:_:)` 的实现就只使用了所有遵循 `Comparable` 协议的类型共有的特性。
而在返回不透明类型的函数中,上述角色发生了互换。不透明类型允许函数实现时,选择一个与调用代码无关的返回类型。比如,下面的例子返回了一个梯形,却没直接输出梯形的底层类型:
```swift
struct Square: Shape {
var size: Int
func draw() -> String {
let line = String(repeating: "*", count: size)
let result = Array<String>(repeating: line, count: size)
return result.joined(separator: "\n")
}
}
func makeTrapezoid() -> some Shape {
let top = Triangle(size: 2)
let middle = Square(size: 2)
let bottom = FlippedShape(shape: top)
let trapezoid = JoinedShape(
top: top,
bottom: JoinedShape(top: middle, bottom: bottom)
)
return trapezoid
}
let trapezoid = makeTrapezoid()
print(trapezoid.draw())
// *
// **
// **
// **
// **
// *
```
这个例子中,`makeTrapezoid()` 函数将返回值类型定义为 `some Shape`;因此,该函数返回遵循 `Shape` 协议的给定类型,而不需指定任何具体类型。这样写 `makeTrapezoid()` 函数可以表明它公共接口的基本性质 —— 返回的是一个几何图形 —— 而不是部分的公共接口生成的特殊类型。上述实现过程中使用了两个三角形和一个正方形,还可以用其他多种方式重写画梯形的函数,都不必改变返回类型。
这个例子凸显了不透明返回类型和泛型的相反之处。`makeTrapezoid()` 中代码可以返回任意它需要的类型,只要这个类型是遵循 `Shape` 协议的,就像调用泛型函数时可以使用任何需要的类型一样。这个函数的调用代码需要采用通用的方式,就像泛型函数的实现代码一样,这样才能让 `makeTrapezoid()` 返回的任何 `Shape` 类型的值都能被正常使用。
你也可以将不透明返回类型和泛型结合起来,下面的两个泛型函数也都返回了遵循 `Shape` 协议的不透明类型。
```swift
func flip<T: Shape>(_ shape: T) -> some Shape {
return FlippedShape(shape: shape)
}
func join<T: Shape, U: Shape>(_ top: T, _ bottom: U) -> some Shape {
JoinedShape(top: top, bottom: bottom)
}
let opaqueJoinedTriangles = join(smallTriangle, flip(smallTriangle))
print(opaqueJoinedTriangles.draw())
// *
// **
// ***
// ***
// **
// *
```
这个例子中 `opaqueJoinedTriangles` 的值和前文 [不透明类型解决的问题](#the-problem-that-opaque-types-solve) 中关于泛型的那个例子中的 `joinedTriangles` 完全一样。不过和前文不一样的是,`flip(_:)``join(_:_:)` 将对泛型参数的操作后的返回结果包装成了不透明类型,这样保证了在结果中泛型参数类型不可见。两个函数都是泛型函数,因为他们都依赖于泛型参数,而泛型参数又将 `FlippedShape``JoinedShape` 所需要的类型信息传递给它们。
如果函数中有多个地方返回了不透明类型,那么所有可能的返回值都必须是同一类型。即使对于泛型函数,不透明返回类型可以使用泛型参数,但仍需保证返回类型唯一。比如,下面就是一个*非法*示例 —— 包含针对 `Square` 类型进行特殊处理的翻转函数。
```swift
func invalidFlip<T: Shape>(_ shape: T) -> some Shape {
if shape is Square {
return shape // 错误:返回类型不一致
}
return FlippedShape(shape: shape) // 错误:返回类型不一致
}
```
如果你调用这个函数时传入一个 `Square` 类型,那么它会返回 `Square` 类型;否则,它会返回一个 `FlippedShape` 类型。这违反了返回值类型唯一的要求,所以 `invalidFlip(_:)` 不正确。修正 `invalidFlip(_:)` 的方法之一就是将针对 `Square` 的特殊处理移入到 `FlippedShape` 的实现中去,这样就能保证这个函数始终返回 `FlippedShape`
```swift
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {
if shape is Square {
return shape.draw()
}
let lines = shape.draw().split(separator: "\n")
return lines.reversed().joined(separator: "\n")
}
}
```
返回类型始终唯一的要求,并不会影响在返回的不透明类型中使用泛型。比如下面的函数,就是在返回的底层类型中使用了泛型参数:
```swift
func `repeat`<T: Shape>(shape: T, count: Int) -> some Collection {
return Array<T>(repeating: shape, count: count)
}
```
这种情况下,返回的底层类型会根据 `T` 的不同而发生变化:但无论什么形状被传入,`repeat(shape:count:)` 都会创建并返回一个元素为相应形状的数组。尽管如此,返回值始终还是同样的底层类型 `[T]` 所以这符合不透明返回类型始终唯一的要求。
## 不透明类型和协议类型的区别 {#differences-between-opaque-types-and-protocol-types}
虽然使用不透明类型作为函数返回值,看起来和返回协议类型非常相似,但这两者有一个主要区别,就在于是否需要保证类型一致性。一个不透明类型只能对应一个具体的类型,即便函数调用者并不能知道是哪一种类型;协议类型可以同时对应多个类型,只要它们都遵循同一协议。总的来说,协议类型更具灵活性,底层类型可以存储更多样的值,而不透明类型对这些底层类型有更强的限定。
比如,这是 `flip(_:)` 方法不采用不透明类型,而采用返回协议类型的版本:
```swift
func protoFlip<T: Shape>(_ shape: T) -> Shape {
return FlippedShape(shape: shape)
}
```
这个版本的 `protoFlip(_:)``flip(_:)` 有相同的函数体,并且它也始终返回唯一类型。但不同于 `flip(_:)``protoFlip(_:)` 返回值其实不需要始终返回唯一类型 —— 返回类型只需要遵循 `Shape` 协议即可。换句话说,`protoFlip(_:)` 比起 `flip(_:)` 对 API 调用者的约束更加松散。它保留了返回多种不同类型的灵活性:
```swift
func protoFlip<T: Shape>(_ shape: T) -> Shape {
if shape is Square {
return shape
}
return FlippedShape(shape: shape)
}
```
修改后的代码根据代表形状的参数的不同,可能返回 `Square` 实例或者 `FlippedShape` 实例,所以同样的函数可能返回完全不同的两个类型。当翻转相同形状的多个实例时,此函数的其他有效版本也可能返回完全不同类型的结果。`protoFlip(_:)` 返回类型的不确定性,意味着很多依赖返回类型信息的操作也无法执行了。举个例子,这个函数的返回结果就不能用 == 运算符进行比较了。
```swift
let protoFlippedTriangle = protoFlip(smallTriangle)
let sameThing = protoFlip(smallTriangle)
protoFlippedTriangle == sameThing // 错误
```
上面的例子中,最后一行的错误来源于多个原因。最直接的问题在于,`Shape` 协议中并没有包含对 == 运算符的声明。如果你尝试加上这个声明,那么你会遇到新的问题,就是 == 运算符需要知道左右两侧参数的类型。这类运算符通常会使用 `Self` 类型作为参数,用来匹配符合协议的具体类型,但是由于将协议当成类型使用时会发生类型擦除,所以并不能给协议加上对 `Self` 的实现要求。
将协议类型作为函数的返回类型能更加灵活,函数只要返回遵循协议的类型即可。然而,更具灵活性导致牺牲了对返回值执行某些操作的能力。上面的例子就说明了为什么不能使用 == 运算符 —— 它依赖于具体的类型信息,而这正是使用协议类型所无法提供的。
这种方法的另一个问题在于,变换形状的操作不能嵌套。翻转三角形的结果是一个 `Shape` 类型的值,而 `protoFlip(_:)` 方法的则将遵循 `Shape` 协议的类型作为形参,然而协议类型的值并不遵循这个协议;`protoFlip(_:)` 的返回值也并不遵循 `Shape` 协议。这就是说 `protoFlip(protoFlip(smallTriange))` 这样的多重变换操作是非法的,因为经过翻转操作后的结果类型并不能作为 `protoFlip(_:)` 的形参。
相比之下不透明类型则保留了底层类型的唯一性。Swift 能够推断出关联类型,这个特点使得作为函数返回值,不透明类型比协议类型有更大的使用场景。比如,下面这个例子是 [泛型](./22_Generics.md) 中讲到的 `Container` 协议:
```swift
protocol Container {
associatedtype Item
var count: Int { get }
subscript(i: Int) -> Item { get }
}
extension Array: Container { }
```
你不能将 `Container` 作为方法的返回类型,因为此协议有一个关联类型。你也不能将它用于对泛型返回类型的约束,因为函数体之外并没有暴露足够多的信息来推断泛型类型。
```swift
// 错误:有关联类型的协议不能作为返回类型。
func makeProtocolContainer<T>(item: T) -> Container {
return [item]
}
// 错误:没有足够多的信息来推断 C 的类型。
func makeProtocolContainer<T, C: Container>(item: T) -> C {
return [item]
}
```
而使用不透明类型 `some Container` 作为返回类型,就能够明确地表达所需要的 API 契约 —— 函数会返回一个集合类型,但并不指明它的具体类型:
```swift
func makeOpaqueContainer<T>(item: T) -> some Container {
return [item]
}
let opaqueContainer = makeOpaqueContainer(item: 12)
let twelve = opaqueContainer[0]
print(type(of: twelve))
// 输出 "Int"
```
`twelve` 的类型可以被推断出为 `Int` 这说明了类型推断适用于不透明类型。在 `makeOpaqueContainer(item:)` 的实现中,底层类型是不透明集合 `[T]`。在上述这种情况下,`T` 就是 `Int` 类型,所以返回值就是整数数组,而关联类型 `Item` 也被推断出为 `Int``Container` 协议中的 `subscipt` 方法会返回 `Item`,这也意味着 `twelve` 的类型也被能推断出为 `Int`

View File

@ -162,9 +162,9 @@ Swift 的*“词法结构lexical structure”* 描述了能构成该语言
true // 布尔值字面量 true // 布尔值字面量
``` ```
字面量本身并不包含类型信息。事实上,一个字面量会被解析为拥有无限的精度,然后 Swift 的类型推导会尝试去推导出这个字面量的类型。比如,在 `let x: Int8 = 42` 这个声明中Swift 使用了显式类型注(`: Int8`)来推导出 `42` 这个整数字面量的类型是 `Int8`。如果没有可用的类型信息, Swift 则会从标准库中定义的字面量类型中推导出一个默认的类型。整数字面量的默认类型是 `Int`,浮点数字面量的默认类型是 `Double`,字符串字面量的默认类型是 `String`,布尔值字面量的默认类型是 `Bool`。比如,在 `let str = "Hello, world"` 这个声明中,字符串 `"Hello, world"` 的默认推导类型就是 `String`。 字面量本身并不包含类型信息。事实上,一个字面量会被解析为拥有无限的精度,然后 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` 的类型注。 当为一个字面量值指定了类型注的时候,这个标注的类型必须能通过这个字面量值实例化。也就是说,这个类型必须符合这些 Swift 标准库协议中的一个:整数字面量的 `IntegerLiteralConvertible` 协议、浮点数字面量的 `FloatingPointLiteralConvertible` 协议、字符串字面量的 `StringLiteralConvertible` 协议以及布尔值字面量的 `BooleanLiteralConvertible` 协议。比如,`Int8` 符合 `IntegerLiteralConvertible` 协议,因此它能在 `let x: Int8 = 42` 这个声明中作为整数字面量 `42` 的类型注
> 字面量语法 > 字面量语法
> >

View File

@ -14,32 +14,33 @@ Swift 语言存在两种类型:命名型类型和复合型类型。*命名型
> 类型语法 > 类型语法
> >
> *类型* → [*数组类型*](#array-type) > *类型* → [函数类型](#function-type)
> >
> *类型* → [*字典类型*](#dictionary-type) > *类型* → [数组类型](#array-type)
> >
> *类型* → [*函数类型*](#function-type) > *类型* → [字典类型](#dictionary-type)
> >
> *类型* → [*类型标识*](#type-identifier) > *类型* → [类型标识](#type-identifier)
> >
> *类型* → [*元组类型*](#tuple-type) > *类型* → [元组类型](#tuple-type)
> >
> *类型* → [*可选类型*](#optional-type) > *类型* → [可选类型](#optional-type)
> >
> *类型* → [*隐式解析可选类型*](#implicitly-unwrapped-optional-type) > *类型* → [隐式解析可选类型](#implicitly-unwrapped-optional-type)
> >
> *类型* → [*协议合成类型*](#protocol-composition-type) > *类型* → [协议合成类型](#protocol-composition-type)
> >
> *类型* → [*元型类型*](#metatype-type) > *类型* →[不透明类型](#opaque-type)
> >
> *类型* → **任意类型** > *类型* → [元型类型](#metatype-type)
> >
> *类型* → **自身类型** > *类型* → [自身类型](#self-type)
> >
> *类型* → [*(类型)*](#type) > *类型* → **Any**
> >
> *类型* → **** [类型](#type) ****
## 类型注解 {#type-annotation} ## 类型注解 {#type-annotation-h}
*类型注解*显式地指定一个变量或表达式的类型。类型注解始于冒号 `:` 终于类型,比如下面两个例子: *类型注解*显式地指定一个变量或表达式的类型。类型注解始于冒号 `:` 终于类型,比如下面两个例子:
```swift ```swift
@ -56,10 +57,9 @@ func someFunction(a: Int) { /* ... */ }
#### type-annotation {#type-annotation} #### type-annotation {#type-annotation}
> *类型注解* → **:** [*特性列表*](./07_Attributes.md#attributes)<sub>可选</sub> **输入输出参数**<sub>可选</sub> [*类型*](#type) > *类型注解* → **:** [*特性列表*](./07_Attributes.md#attributes)<sub>可选</sub> **输入输出参数**<sub>可选</sub> [*类型*](#type)
>
## 类型标识符 {#type-identifier} ## 类型标识符 {#type-identifier-h}
类型标识符引用命名型类型,还可引用命名型或复合型类型的别名。 *类型标识符*引用命名型类型,还可引用命名型或复合型类型的别名。
大多数情况下,类型标识符引用的是与之同名的命名型类型。例如类型标识符 `Int` 引用命名型类型 `Int`,同样,类型标识符 `Dictionary<String, Int>` 引用命名型类型 `Dictionary<String, Int>` 大多数情况下,类型标识符引用的是与之同名的命名型类型。例如类型标识符 `Int` 引用命名型类型 `Int`,同样,类型标识符 `Dictionary<String, Int>` 引用命名型类型 `Dictionary<String, Int>`
@ -85,10 +85,9 @@ var someValue: ExampleModule.MyType
#### type-name {#type-name} #### type-name {#type-name}
> *类型名称* → [*标识符*](./02_Lexical_Structure.md#identifier) > *类型名称* → [*标识符*](./02_Lexical_Structure.md#identifier)
>
## 元组类型 {#tuple-type} ## 元组类型 {#tuple-type-h}
元组类型是使用括号括起来的零个或多个类型,类型间用逗号隔开。 *元组类型*是使用括号括起来的零个或多个类型,类型间用逗号隔开。
你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号 `(:)` 组成。[函数和多返回值](../chapter2/06_Functions.md#functions_with_multiple_return_values) 章节里有一个展示上述特性的例子。 你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号 `(:)` 组成。[函数和多返回值](../chapter2/06_Functions.md#functions_with_multiple_return_values) 章节里有一个展示上述特性的例子。
@ -122,8 +121,8 @@ someTuple = (left: 5, right: 5) // 错误:命名类型不匹配
> *元素名* → [*标识符*](./02_Lexical_Structure.md#identifier) > *元素名* → [*标识符*](./02_Lexical_Structure.md#identifier)
> >
## 函数类型 {#function-type} ## 函数类型 {#function-type-h}
函数类型表示一个函数、方法或闭包的类型,它由参数类型和返回值类型组成,中间用箭头(`->`)隔开: *函数类型*表示一个函数、方法或闭包的类型,它由参数类型和返回值类型组成,中间用箭头(`->`)隔开:
> `参数类型`->`返回值类型` > `参数类型`->`返回值类型`
@ -191,7 +190,7 @@ func takesTwoFunctions(first: (Any) -> Void, second: (Any) -> Void) {
上述例子里的被标记为“错误”的四个函数调用会产生编译错误。因为参数 `first``second` 是非逃逸函数,它们不能够作为参数被传递到另一个非闭包函数。相对的, 标记“正确”的两个函数不会产生编译错误。这些函数调用不会违反限制,因为 `external` 不是 `takesTwoFunctions(first:second:)` 的参数之一。 上述例子里的被标记为“错误”的四个函数调用会产生编译错误。因为参数 `first``second` 是非逃逸函数,它们不能够作为参数被传递到另一个非闭包函数。相对的, 标记“正确”的两个函数不会产生编译错误。这些函数调用不会违反限制,因为 `external` 不是 `takesTwoFunctions(first:second:)` 的参数之一。
如果你需要避免这个限制,标记其中之一的参数为逃逸,或者使用 `withoutActuallyEscaping(_:do:)` 函数临时地转换非逃逸函数的其中一个参数为逃逸函数。关于避免内存访问冲突,可以参阅[内存安全](../chapter2/24_Memory_Safety.md)。 如果你需要避免这个限制,标记其中之一的参数为逃逸,或者使用 `withoutActuallyEscaping(_:do:)` 函数临时地转换非逃逸函数的其中一个参数为逃逸函数。关于避免内存访问冲突,可以参阅 [内存安全](../chapter2/24_Memory_Safety.md)。
> 函数类型语法 > 函数类型语法
> >
@ -219,7 +218,7 @@ func takesTwoFunctions(first: (Any) -> Void, second: (Any) -> Void) {
> *参数标签* → [*标识符*](./02_Lexical_Structure.md#identifier) > *参数标签* → [*标识符*](./02_Lexical_Structure.md#identifier)
> >
## 数组类型 {#array-type} ## 数组类型 {#array-type-h}
Swift 语言为标准库中定义的 `Array<Element>` 类型提供了如下语法糖: Swift 语言为标准库中定义的 `Array<Element>` 类型提供了如下语法糖:
> [`类型`] > [`类型`]
@ -251,7 +250,7 @@ var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
> *数组类型* → **[** [*类型*](#type) **]** > *数组类型* → **[** [*类型*](#type) **]**
> >
## 字典类型 {#dictionary-type} ## 字典类型 {#dictionary-type-h}
Swift 语言为标准库中定义的 `Dictionary<Key, Value>` 类型提供了如下语法糖: Swift 语言为标准库中定义的 `Dictionary<Key, Value>` 类型提供了如下语法糖:
> [`键类型` : `值类型`] > [`键类型` : `值类型`]
@ -279,7 +278,7 @@ let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]
> *字典类型* → **[** [*类型*](#type) **:** [*类型*](#type) **]** > *字典类型* → **[** [*类型*](#type) **:** [*类型*](#type) **]**
> >
## 可选类型 {#optional-type} ## 可选类型 {#optional-type-h}
Swift 定义后缀 `?` 来作为标准库中定义的命名型类型 `Optional<Wrapped>` 的语法糖。换句话说,下面两个声明是等价的: Swift 定义后缀 `?` 来作为标准库中定义的命名型类型 `Optional<Wrapped>` 的语法糖。换句话说,下面两个声明是等价的:
```swift ```swift
@ -311,7 +310,7 @@ optionalInteger! // 42
> *可选类型* → [*类型*](#type) **?** > *可选类型* → [*类型*](#type) **?**
> >
## 隐式解析可选类型 {#implicitly-unwrapped-optional-type} ## 隐式解析可选类型 {#implicitly-unwrapped-optional-type-h}
当可以被访问时Swift 语言定义后缀 `!` 作为标准库中命名类型 `Optional<Wrapped>` 的语法糖,来实现自动解包的功能。如果尝试对一个值为 `nil` 的可选类型进行隐式解包,将会产生运行时错误。因为隐式解包,下面两个声明等价: 当可以被访问时Swift 语言定义后缀 `!` 作为标准库中命名类型 `Optional<Wrapped>` 的语法糖,来实现自动解包的功能。如果尝试对一个值为 `nil` 的可选类型进行隐式解包,将会产生运行时错误。因为隐式解包,下面两个声明等价:
```swift ```swift
@ -346,13 +345,12 @@ let implicitlyUnwrappedArray: [Int]! // 正确
> *隐式解析可选类型* → [*类型*](#type) **!** > *隐式解析可选类型* → [*类型*](#type) **!**
> >
## 协议合成类型 {#protocol-composition-type} ## 协议合成类型 {#protocol-composition-type-h}
协议合成类型定义了一种遵循协议列表中每个指定协议的类型,或者一个现有类型的子类并遵循协议列表中每个指定协议。协议合成类型只能用在类型注解、泛型参数子句和泛型 `where` 子句中指定类型。 *协议合成类型*定义了一种遵循协议列表中每个指定协议的类型,或者一个现有类型的子类并遵循协议列表中每个指定协议。协议合成类型只能用在类型注解、泛型参数子句和泛型 `where` 子句中指定类型。
协议合成类型的形式如下: 协议合成类型的形式如下:
> `Protocol 1` & `Procotol 2` > `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`
@ -378,10 +376,34 @@ typealias PQR = PQ & Q & R
#### protocol-composition-continuation {#protocol-composition-continuation} #### protocol-composition-continuation {#protocol-composition-continuation}
> *协议合成延续* → [*协议标识符*](#protocol-identifier) | [*协议合成类型*](#protocol-composition-type) > *协议合成延续* → [*协议标识符*](#protocol-identifier) | [*协议合成类型*](#protocol-composition-type)
>
## 类型 {#metatype-type} ## 不透明类型 {#opaque-type-h}
元类型是指任意类型的类型,包括类类型、结构体类型、枚举类型和协议类型。
*不透明类型*定义了遵循某个协议或者合成协议的类型,但不需要指明底层的具体类型。
不透明类型可以作为函数或下标的返回值,亦或是属性的类型使用。
不透明类型不能作为元组类型的一部分或范型类型使用,比如数组元素类型或者可选值的包装类型。
不透明类型的形式如下:
> some `constraint`
*constraint* 可以是类类型,协议类型,协议组合类型或者 `Any`。值只有当它遵循该协议或者组合协议,或者从该类继承的时候,才能作为这个不透明类型的实例使用。和不透明值交互的代码只能使用该值定义在 *constraint* 上的接口。
协议声明里不能包括不透明类型。类不能使用不透明类型作为非 final 方法的返回值。
使用不透明类型作为返回值的函数必须返回单一公用底层类型。返回的类型可以包含函数范型类型参数的一部分。举个例子,函数 `someFunction<T>()` 可以返回类型 `T` 或者 `Dictionary<String,T>` 的值。
> 不透明类型语法
#### opaque-type {#opaque-type}
> *不透明类型* → **some** [type](#type)
## 元类型 {#metatype-type-h}
*元类型*是指任意类型的类型,包括类类型、结构体类型、枚举类型和协议类型。
类、结构体或枚举类型的元类型是相应的类型名紧跟 `.Type`。协议类型的元类型——并不是运行时遵循该协议的具体类型——是该协议名字紧跟 `.Protocol`。比如,类 `SomeClass` 的元类型就是 `SomeClass.Type`,协议 `SomeProtocol` 的元类型就是 `SomeProtocal.Protocol` 类、结构体或枚举类型的元类型是相应的类型名紧跟 `.Type`。协议类型的元类型——并不是运行时遵循该协议的具体类型——是该协议名字紧跟 `.Protocol`。比如,类 `SomeClass` 的元类型就是 `SomeClass.Type`,协议 `SomeProtocol` 的元类型就是 `SomeProtocal.Protocol`
@ -428,10 +450,48 @@ let anotherInstance = metatype.init(string: "some string")
#### metatype-type {#metatype-type} #### metatype-type {#metatype-type}
> *元类型* → [*类型*](#type) **.** **Type** | [*类型*](#type) **.** **Protocol** > *元类型* → [*类型*](#type) **.** **Type** | [*类型*](#type) **.** **Protocol**
>
## 类型继承子句 {#type-inheritance-clause} ## 自身类型 {#self-type-h}
类型继承子句被用来指定一个命名型类型继承自哪个类、采纳哪些协议。类型继承子句开始于冒号 `:`,其后是类型标识符列表。
`Self` 类型不是具体的类型,而是让你更方便的引用当前类型,不需要重复或者知道该类的名字。
在协议声明或者协议成员声明时,`Self` 类型引用的是最终遵循该协议的类型。
在结构体,类或者枚举值声明时,`Self` 类型引用的是声明的类型。在某个类型成员声明时,`Self` 类型引用的是该类型。在类成员声明时,`Self` 可以在方法的返回值和方法体中使用,但不能在其他上下文中使用。举个例子,下面的代码演示了返回值是 `Self` 的实例方法 `f`
```swift
class Superclass {
func f() -> Self { return self }
}
let x = Superclass()
print(type(of: x.f()))
// 打印 "Superclass"
class Subclass: Superclass { }
let y = Subclass()
print(type(of: y.f()))
// 打印 "Subclass"
let z: Superclass = Subclass()
print(type(of: z.f()))
// 打印 "Subclass"
```
上面例子的最后一部分表明 `Self` 引用的是值 `z` 的运行时类型 `Subclass` ,而不是变量本身的编译时类型 `Superclass`
在嵌套类型声明时,`Self` 类型引用的是最内层声明的类型。
`Self` 类型引用的类型和 Swift 标准库中 [type(of:)](https://developer.apple.com/documentation/swift/2885064-type) 函数的结果一样。使用 `Self.someStaticMember` 访问当前类型中的成员和使用 `type(of: self).someStaticMember` 是一样的。
> 自身类型语法
#### self-type{#self-type}
> *自身类型* → **Self**
## 类型继承子句 {#type-inheritance-clause-h}
*类型继承子句*被用来指定一个命名型类型继承自哪个类、采纳哪些协议。类型继承子句开始于冒号 `:`,其后是类型标识符列表。
类可以继承自单个超类,并遵循任意数量的协议。当定义一个类时,超类的名字必须出现在类型标识符列表首位,然后跟上该类需要遵循的任意数量的协议。如果一个类不是从其它类继承而来,那么列表可以以协议开头。关于类继承更多的讨论和例子,请参阅 [继承](../chapter2/13_Inheritance.md)。 类可以继承自单个超类,并遵循任意数量的协议。当定义一个类时,超类的名字必须出现在类型标识符列表首位,然后跟上该类需要遵循的任意数量的协议。如果一个类不是从其它类继承而来,那么列表可以以协议开头。关于类继承更多的讨论和例子,请参阅 [继承](../chapter2/13_Inheritance.md)。
@ -450,11 +510,9 @@ let anotherInstance = metatype.init(string: "some string")
> *类型继承列表* → [*类型标识符*](#type-identifier) | [*类型标识符*](#type-identifier) **,** [*类型继承列表*](#type-inheritance-list) > *类型继承列表* → [*类型标识符*](#type-identifier) | [*类型标识符*](#type-identifier) **,** [*类型继承列表*](#type-inheritance-list)
> >
#### class-requirement {#class-requirement}
## 类型推断
## 类型推断 {#type-inference} Swift 广泛使用*类型推断*,从而允许你省略代码中很多变量和表达式的类型或部分类型。比如,对于 `var x: Int = 0`,你可以完全省略类型而简写成 `var x = 0`,编译器会正确推断出 `x` 的类型 `Int`。类似的,当完整的类型可以从上下文推断出来时,你也可以省略类型的一部分。比如,如果你写了 `let dict: Dictionary = ["A" : 1]`,编译器能推断出 `dict` 的类型是 `Dictionary<String, Int>`
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`)。 在上面的两个例子中,类型信息从表达式树的叶子节点传向根节点。也就是说,`var x: Int = 0``x` 的类型首先根据 `0` 的类型进行推断,然后将该类型信息传递到根节点(变量 `x`)。

View File

@ -57,7 +57,7 @@ try 表达式由 `try` 运算符加上紧随其后的可抛出错误的表达式
如果可抛出错误的表达式抛出了错误,将会引发运行时错误。 如果可抛出错误的表达式抛出了错误,将会引发运行时错误。
在二进制运算符左侧的表达式被标记上 `try``try?` 或者 `try!` 时,这个运算符对整个二进制表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。 在二运算符左侧的表达式被标记上 `try``try?` 或者 `try!` 时,这个运算符对整个二表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。
```swift ```swift
sum = try someThrowingFunction() + anotherThrowingFunction() // try 对两个函数调用都产生作用 sum = try someThrowingFunction() + anotherThrowingFunction() // try 对两个函数调用都产生作用
@ -65,7 +65,7 @@ sum = try (someThrowingFunction() + anotherThrowingFunction()) // try 对两个
sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try 只对第一个函数调用产生作用 sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try 只对第一个函数调用产生作用
``` ```
`try` 表达式不能出现在二进制运算符的的右侧,除非二进制运算符是赋值运算符或者 `try` 表达式是被圆括号括起来的。 `try` 表达式不能出现在二运算符的的右侧,除非二运算符是赋值运算符或者 `try` 表达式是被圆括号括起来的。
关于 `try``try?``try!` 的更多信息,以及该如何使用的例子,请参阅 [错误处理](../chapter2/17_Error_Handling.md)。 关于 `try``try?``try!` 的更多信息,以及该如何使用的例子,请参阅 [错误处理](../chapter2/17_Error_Handling.md)。
> Try 表达式语法 > Try 表达式语法
@ -275,7 +275,7 @@ var emptyDictionary: [String : Double] = [:]
Xcode 使用 playground 字面量对程序编辑器中的颜色、文件或者图片创建可交互的展示。在 Xcode 之外的空白文本中playground 字面量使用一种特殊的字面量语法来展示。 Xcode 使用 playground 字面量对程序编辑器中的颜色、文件或者图片创建可交互的展示。在 Xcode 之外的空白文本中playground 字面量使用一种特殊的字面量语法来展示。
更多关于在 Xcode 中使用 playground 字面量的信息,请参阅 [添加颜色、文件或图片字面量](https://help.apple.com/xcode/mac/current/#/dev4c60242fc) 更多关于在 Xcode 中使用 playground 字面量的信息,请参阅 [添加颜色、文件或图片字面量](https://help.apple.com/xcode/mac/current/#/dev4c60242fc)
> 字面量表达式语法 > 字面量表达式语法
> >
@ -430,7 +430,6 @@ struct Point {
```swift ```swift
{ (parameters) -> return type in { (parameters) -> return type in
>
statements statements
} }
``` ```
@ -448,7 +447,6 @@ struct Point {
```swift ```swift
myFunction { myFunction {
(x: Int, y: Int) -> Int in (x: Int, y: Int) -> Int in
>
return x + y return x + y
} }
@ -466,7 +464,7 @@ myFunction { $0 + $1 }
使用闭包表达式时,可以不必将其存储在一个变量或常量中,例如作为函数调用的一部分来立即使用一个闭包。在上面的例子中,传入 `myFunction` 的闭包表达式就是这种立即使用类型的闭包。因此,一个闭包是否逃逸与其使用时的上下文相关。一个会被立即调用或者作为函数的非逃逸参数传递的闭包表达式是非逃逸的,否则,这个闭包表达式是逃逸的。 使用闭包表达式时,可以不必将其存储在一个变量或常量中,例如作为函数调用的一部分来立即使用一个闭包。在上面的例子中,传入 `myFunction` 的闭包表达式就是这种立即使用类型的闭包。因此,一个闭包是否逃逸与其使用时的上下文相关。一个会被立即调用或者作为函数的非逃逸参数传递的闭包表达式是非逃逸的,否则,这个闭包表达式是逃逸的。
关于逃逸闭包的内容,请参阅[逃逸闭包](./chapter2/07_Closures.md#escaping_closures) 关于逃逸闭包的内容,请参阅 [逃逸闭包](./chapter2/07_Closures.md#escaping_closures)
## 捕获列表 {#capture-lists} ## 捕获列表 {#capture-lists}
默认情况下,闭包会捕获附近作用域中的常量和变量,并使用强引用指向它们。你可以通过一个*捕获列表*来显式指定它的捕获行为。 默认情况下,闭包会捕获附近作用域中的常量和变量,并使用强引用指向它们。你可以通过一个*捕获列表*来显式指定它的捕获行为。
@ -729,7 +727,6 @@ let myGreeting = greetings[keyPath: \[String].[1]]
var index = 2 var index = 2
let path = \[String].[index] let path = \[String].[index]
let fn: ([String]) -> String = { strings in strings[index] } let fn: ([String]) -> String = { strings in strings[index] }
>
print(greetings[keyPath: path]) print(greetings[keyPath: path])
// 打印 "bonjour" // 打印 "bonjour"
@ -775,7 +772,7 @@ print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth
// 打印 "64" // 打印 "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 与 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 表达式语法 > key-path 表达式语法
> >
@ -840,7 +837,6 @@ extension SomeClass {
func doSomething(_ x: String) { } func doSomething(_ x: String) { }
} }
let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void) let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void)
>
``` ```
由于选择器是在编译时创建的,因此编译器可以检查方法或者属性是否存在,以及是否在运行时暴露给了 Objective-C 。 由于选择器是在编译时创建的,因此编译器可以检查方法或者属性是否存在,以及是否在运行时暴露给了 Objective-C 。
@ -903,7 +899,7 @@ print(keyPath == c.getSomeKeyPath())
由于 key-path 字符串表达式在编译期才创建,编译期可以检查属性是否存在,以及属性是否暴露给 Objective-C 运行时。 由于 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)
> 注意 > 注意
> >
@ -1036,7 +1032,6 @@ class SomeSubClass: SomeSuperClass {
```swift ```swift
// 类型注解是必须的,因为 String 类型有多种构造器 // 类型注解是必须的,因为 String 类型有多种构造器
let initializer: Int -> String = String.init let initializer: Int -> String = String.init
>
let oneTwoThree = [1, 2, 3].map(initializer).reduce("", combine: +) let oneTwoThree = [1, 2, 3].map(initializer).reduce("", combine: +)
print(oneTwoThree) print(oneTwoThree)
// 打印“123” // 打印“123”
@ -1087,9 +1082,9 @@ t.0 = t.1
对于模块的成员来说,只能直接访问顶级声明中的成员。 对于模块的成员来说,只能直接访问顶级声明中的成员。
使用 `dynamicMemberLookup` 属性声明的类型包含可以在运行时查找的成员,具体请参阅 [属性](./07_Attributes.md) 使用 `dynamicMemberLookup` 属性声明的类型包含可以在运行时查找的成员,具体请参阅 [属性](./07_Attributes.md)
为了区分只有参数名有所不同的方法或构造器,在圆括号中写出参数名,参数名后紧跟一个冒号,对于没有参数名的参数,使用下划线代替参数名。而对于重载方法,则需使用类型注进行区分。例如: 为了区分只有参数名有所不同的方法或构造器,在圆括号中写出参数名,参数名后紧跟一个冒号,对于没有参数名的参数,使用下划线代替参数名。而对于重载方法,则需使用类型注进行区分。例如:
```swift ```swift
class SomeClass { class SomeClass {
@ -1106,7 +1101,6 @@ let b = instance.someMethod(_:y:) // 无歧义
let d = instance.overloadedMethod // 有歧义 let d = instance.overloadedMethod // 有歧义
let d = instance.overloadedMethod(_:y:) // 有歧义 let d = instance.overloadedMethod(_:y:) // 有歧义
let d: (Int, Bool) -> Void = instance.overloadedMethod(_:y:) // 无歧义 let d: (Int, Bool) -> Void = instance.overloadedMethod(_:y:) // 无歧义
>
``` ```
如果点号(`.`)出现在行首,它会被视为显式成员表达式的一部分,而不是隐式成员表达式的一部分。例如如下代码所展示的被分为多行的链式方法调用: 如果点号(`.`)出现在行首,它会被视为显式成员表达式的一部分,而不是隐式成员表达式的一部分。例如如下代码所展示的被分为多行的链式方法调用:
@ -1115,7 +1109,6 @@ let d: (Int, Bool) -> Void = instance.overloadedMethod(_:y:) // 无歧义
let x = [10, 3, 20, 15, 4] let x = [10, 3, 20, 15, 4]
.sort() .sort()
.filter { $0 > 5 } .filter { $0 > 5 }
>
.map { $0 * 100 } .map { $0 * 100 }
``` ```
@ -1232,7 +1225,6 @@ if let unwrappedC = c {
```swift ```swift
func someFunctionWithSideEffects() -> Int { func someFunctionWithSideEffects() -> Int {
>
// 译者注:为了能看出此函数是否被执行,加上了一句打印 // 译者注:为了能看出此函数是否被执行,加上了一句打印
print("someFunctionWithSideEffects") print("someFunctionWithSideEffects")
return 42 return 42

View File

@ -135,9 +135,9 @@ print("The second number is \(secondNumber).")
// 打印“The second number is 42.” // 打印“The second number is 42.”
``` ```
当常量名称的类型(`:` 类型)可以被推断出时,类型注在常量声明中是可选的,正如 [类型推断](./03_Types.md#type_inference) 中所描述的。 当常量名称的类型(`:` 类型)可以被推断出时,类型注在常量声明中是可选的,正如 [类型推断](./03_Types.md#type_inference) 中所描述的。
声明一个常量类型属性要使用 `static` 声明修饰符。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties)中有介绍。 声明一个常量类型属性要使用 `static` 声明修饰符。类的常量类型属性总是隐式地被标记为 `final` ;你无法用 `class``final` 声明修饰符实现允许或禁止被子类重写的目的。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties) 中有介绍。
如果还想获得更多关于常量的信息或者想在使用中获得帮助,请参阅 [常量和变量](../chapter2/01_The_Basics.md#constants_and_variables) 和 [存储属性](../chapter2/10_Properties.md#stored_properties)。 如果还想获得更多关于常量的信息或者想在使用中获得帮助,请参阅 [常量和变量](../chapter2/01_The_Basics.md#constants_and_variables) 和 [存储属性](../chapter2/10_Properties.md#stored_properties)。
@ -187,7 +187,7 @@ var 变量名称: 类型 = 表达式
可以在全局范围,函数内部,或者在类和结构体的声明中使用这种形式来声明一个变量。当变量以这种形式在全局范围或者函数内部被声明时,它代表一个存储型变量。当它在类或者结构体中被声明时,它代表一个*存储型变量属性stored variable property*。 可以在全局范围,函数内部,或者在类和结构体的声明中使用这种形式来声明一个变量。当变量以这种形式在全局范围或者函数内部被声明时,它代表一个存储型变量。当它在类或者结构体中被声明时,它代表一个*存储型变量属性stored variable property*。
用于初始化的表达式不可以在协议的声明中出现,在其他情况下,该表达式是可选的。如果没有初始化表达式,那么变量声明必须包含类型注(`:` *type*)。 用于初始化的表达式不可以在协议的声明中出现,在其他情况下,该表达式是可选的。如果没有初始化表达式,那么变量声明必须包含类型注`:` *type*)。
如同常量声明,如果变量名称是元组形式,元组中每一项的名称都会和初始化表达式中对应的值进行绑定。 如同常量声明,如果变量名称是元组形式,元组中每一项的名称都会和初始化表达式中对应的值进行绑定。
@ -236,7 +236,7 @@ var 变量名称: 类型 = 表达式 {
可以为任何存储型属性添加观察器。也可以通过重写父类属性的方式为任何继承的属性(无论是存储型还是计算型的)添加观察器 可以为任何存储型属性添加观察器。也可以通过重写父类属性的方式为任何继承的属性(无论是存储型还是计算型的)添加观察器
,正如 [重写属性观察器](../chapter2/13_Inheritance.md#overriding_property_observers) 中所描述的。 ,正如 [重写属性观察器](../chapter2/13_Inheritance.md#overriding_property_observers) 中所描述的。
用于初始化的表达式在类或者结构的声明中是可选的,但是在其他声明中则是必须的。如果可以从初始化表达式中推断出类型信息,那么可以不提供类型注。 用于初始化的表达式在类或者结构的声明中是可选的,但是在其他声明中则是必须的。如果可以从初始化表达式中推断出类型信息,那么可以不提供类型注
当变量或属性的值被改变时,`willSet``didSet` 观察器提供了一种观察方法。观察器会在变量的值被改变时调用,但不会在初始化时被调用。 当变量或属性的值被改变时,`willSet``didSet` 观察器提供了一种观察方法。观察器会在变量的值被改变时调用,但不会在初始化时被调用。
@ -251,11 +251,6 @@ var 变量名称: 类型 = 表达式 {
### 类型变量属性 {#type-variable-properties} ### 类型变量属性 {#type-variable-properties}
要声明一个类型变量属性,用 `static` 声明修饰符标记该声明。类可以改用 `class` 声明修饰符标记类的类型计算型属性从而允许子类重写超类的实现。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties) 章节有详细讨论。 要声明一个类型变量属性,用 `static` 声明修饰符标记该声明。类可以改用 `class` 声明修饰符标记类的类型计算型属性从而允许子类重写超类的实现。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties) 章节有详细讨论。
> 注意
>
> 在一个类声明中,使用关键字 `static` 与同时使用 `class` 和 `final` 去标记一个声明的效果相同。
>
#### grammer_of_a_variable_declaration {#grammer-of-a-variable-declaration} #### grammer_of_a_variable_declaration {#grammer-of-a-variable-declaration}
> 变量声明语法 > 变量声明语法
@ -264,15 +259,15 @@ var 变量名称: 类型 = 表达式 {
#### variable-declaration {#variable-declaration} #### variable-declaration {#variable-declaration}
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*模式构造器列表*](#pattern-initializer-list) > *变量声明* → [*变量声明头*](#variable-declaration-head) [*模式构造器列表*](#pattern-initializer-list)
> >
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型注*](03_Types.md#type-annotation) [*代码块*](#code-block) > *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型注*](03_Types.md#type-annotation) [*代码块*](#code-block)
> >
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型注*](03_Types.md#type-annotation) [*getter-setter 代码块*](#getter-setter-block) > *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型注*](03_Types.md#type-annotation) [*getter-setter 代码块*](#getter-setter-block)
> >
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型注*](03_Types.md#type-annotation) [*getter-setter 关键字代码块*](#getter-setter-keyword-block) > *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型注*](03_Types.md#type-annotation) [*getter-setter 关键字代码块*](#getter-setter-keyword-block)
> >
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*构造器*](#initializer) [*willSet-didSet 代码块*](#willSet-didSet-block) > *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*构造器*](#initializer) [*willSet-didSet 代码块*](#willSet-didSet-block)
> >
> *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型注*](03_Types.md#type-annotation) [*构造器*](#initializer)<sub>可选</sub> [*willSet-didSet 代码块*](#willSet-didSet-block) > *变量声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型注*](03_Types.md#type-annotation) [*构造器*](#initializer)<sub>可选</sub> [*willSet-didSet 代码块*](#willSet-didSet-block)
> >
@ -356,20 +351,16 @@ typealias 类型别名 = 现存类型
```swift ```swift
typealias StringDictionary<Value> = Dictionary<String, Value> typealias StringDictionary<Value> = Dictionary<String, Value>
>
// 下列两个字典拥有同样的类型 // 下列两个字典拥有同样的类型
var dictionary1: StringDictionary<Int> = [:] var dictionary1: StringDictionary<Int> = [:]
>
var dictionary2: Dictionary<String, Int> = [:] var dictionary2: Dictionary<String, Int> = [:]
>
``` ```
当一个类型别名带着泛型参数一起被声明时,这些参数的约束必须与现有参数的约束完全匹配。例如: 当一个类型别名带着泛型参数一起被声明时,这些参数的约束必须与现有参数的约束完全匹配。例如:
```swift ```swift
typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int> typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>
>
``` ```
因为类型别名可以和现有类型相互交换使用,类型别名不可以引入额外的类型约束。 因为类型别名可以和现有类型相互交换使用,类型别名不可以引入额外的类型约束。
@ -389,7 +380,6 @@ protocol Sequence {
} }
func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int { func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
>
// ... // ...
} }
``` ```
@ -424,7 +414,6 @@ func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
```swift ```swift
func 函数名称(参数列表) -> 返回类型 { func 函数名称(参数列表) -> 返回类型 {
>
语句 语句
} }
``` ```
@ -439,6 +428,8 @@ func 函数名称(参数列表) {
每个参数的类型都要标明,因为它们不能被推断出来。如果您在某个参数类型前面加上了 `inout`,那么这个参数就可以在这个函数作用域当中被修改。更多关于 `inout` 参数的讨论,请参阅 [输入输出参数](#in-out_parameters)。 每个参数的类型都要标明,因为它们不能被推断出来。如果您在某个参数类型前面加上了 `inout`,那么这个参数就可以在这个函数作用域当中被修改。更多关于 `inout` 参数的讨论,请参阅 [输入输出参数](#in-out_parameters)。
函数声明中语句只包含一个表达式,可以理解为返回该表达式的值。
函数可以使用元组类型作为返回类型来返回多个值。 函数可以使用元组类型作为返回类型来返回多个值。
函数定义可以出现在另一个函数声明内。这种函数被称作*嵌套函数nested function*。 函数定义可以出现在另一个函数声明内。这种函数被称作*嵌套函数nested function*。
@ -456,7 +447,6 @@ func 函数名称(参数列表) {
```swift ```swift
func f(x: Int, y: Int) -> Int { return x + y } func f(x: Int, y: Int) -> Int { return x + y }
>
f(x: 1, y: 2) // 参数 x 和 y 都有标签 f(x: 1, y: 2) // 参数 x 和 y 都有标签
``` ```
@ -495,7 +485,6 @@ repeatGreeting("Hello, world!", count: 2) // count 有标签, greeting 没有
```swift ```swift
func someFunction(a: inout Int) -> () -> Int { func someFunction(a: inout Int) -> () -> Int {
>
return { [a] in return a + 1 } return { [a] in return a + 1 }
} }
``` ```
@ -535,7 +524,7 @@ _ : 参数类型
```swift ```swift
func f(x: Int = 42) -> Int { return x } func f(x: Int = 42) -> Int { return x }
>
f() // 有效,使用默认值 f() // 有效,使用默认值
f(7) // 有效,提供了值 f(7) // 有效,提供了值
f(x: 7) // 无效,该参数没有外部名称 f(x: 7) // 无效,该参数没有外部名称
@ -546,14 +535,13 @@ f(x: 7) // 无效,该参数没有外部名称
子类重写超类中的方法必须以 `override` 声明修饰符标记。重写方法时不使用 `override` 修饰符,或者被 `override` 修饰符修饰的方法并未对超类方法构成重写,都会导致编译错误。 子类重写超类中的方法必须以 `override` 声明修饰符标记。重写方法时不使用 `override` 修饰符,或者被 `override` 修饰符修饰的方法并未对超类方法构成重写,都会导致编译错误。
枚举或者结构体中的类型方法,要以 `static` 声明修饰符标记,而对于类中的类型方法,除了使用 `static`,还可使用 `class` 声明修饰符标记。类中使用 `class` 声明修饰的方法可以被子类实现重写;类中使用 `static` 声明修饰的方法不可被重写。 枚举或者结构体中的类型方法,要以 `static` 声明修饰符标记,而对于类中的类型方法,除了使用 `static`,还可使用 `class` 声明修饰符标记。类中使用 `class` 声明修饰的方法可以被子类实现重写;类中使用 `class final` `static` 声明修饰的方法不可被重写。
### 抛出错误的函数和方法 {#throwing-functions-and-methods} ### 抛出错误的函数和方法 {#throwing-functions-and-methods}
可以抛出错误的函数或方法必须使用 `throws` 关键字标记。这类函数和方法被称为抛出函数和抛出方法。它们有着下面的形式: 可以抛出错误的函数或方法必须使用 `throws` 关键字标记。这类函数和方法被称为抛出函数和抛出方法。它们有着下面的形式:
```swift ```swift
func 函数名称(参数列表) throws -> 返回类型 { func 函数名称(参数列表) throws -> 返回类型 {
>
语句 语句
} }
``` ```
@ -571,7 +559,6 @@ func 函数名称(参数列表) throws -> 返回类型 {
```swift ```swift
func someFunction(callback: () throws -> Void) rethrows { func someFunction(callback: () throws -> Void) rethrows {
>
try callback() try callback()
} }
``` ```
@ -583,7 +570,6 @@ func alwaysThrows() throws {
throw SomeError.error throw SomeError.error
} }
func someFunction(callback: () throws -> Void) rethrows { func someFunction(callback: () throws -> Void) rethrows {
>
do { do {
try callback() try callback()
try alwaysThrows() // 非法, alwaysThrows() 不是一个抛出函数类型的参数 try alwaysThrows() // 非法, alwaysThrows() 不是一个抛出函数类型的参数
@ -598,7 +584,7 @@ func someFunction(callback: () throws -> Void) rethrows {
### 永不返回的函数 {#functions-that-never-return} ### 永不返回的函数 {#functions-that-never-return}
Swift 定义了 `Never` 类型,它表示函数或者方法不会返回给它的调用者。`Never` 返回类型的函数或方法可以称为不归,不归函数、方法要么引发不可恢复的错误,要么永远不停地运作,这会使调用后本应执行得代码就不再执行了。但即使是不归函数、方法,抛错函数和重抛出函数也可以将程序控制转移到合适的 `catch` 代码块。 Swift 定义了 `Never` 类型,它表示函数或者方法不会返回给它的调用者。`Never` 返回类型的函数或方法可以称为不归,不归函数、方法要么引发不可恢复的错误,要么永远不停地运作,这会使调用后本应执行得代码就不再执行了。但即使是不归函数、方法,抛错函数和重抛出函数也可以将程序控制转移到合适的 `catch` 代码块。
不归函数、方法可以在 guard 语句的 else 字句中调用,具体讨论在[*Guard 语句*](./05_Statements.md#guard_statements)。 不归函数、方法可以在 guard 语句的 else 字句中调用,具体讨论在 [*Guard 语句*](./05_Statements.md#guard_statements)。
你可以重写一个不归方法,但是新的方法必须保持原有的返回类型和没有返回的行为。 你可以重写一个不归方法,但是新的方法必须保持原有的返回类型和没有返回的行为。
@ -653,11 +639,11 @@ Swift 定义了 `Never` 类型,它表示函数或者方法不会返回给它
> >
#### parameter {#parameter} #### parameter {#parameter}
> >
> *参数* → [*外部参数名*](#external-parameter-name)<sub>可选</sub> [*内部参数名*](#local-parameter-name) [*类型注*](03_Types.md#type-annotation) [*默认参数子句*](#default-argument-clause)<sub>可选</sub> > *参数* → [*外部参数名*](#external-parameter-name)<sub>可选</sub> [*内部参数名*](#local-parameter-name) [*类型注*](03_Types.md#type-annotation) [*默认参数子句*](#default-argument-clause)<sub>可选</sub>
> >
> *参数* → [*外部参数名*](#external-parameter-name)<sub>可选</sub> [*内部参数名*](#local-parameter-name) [*类型注*](03_Types.md#type-annotation) > *参数* → [*外部参数名*](#external-parameter-name)<sub>可选</sub> [*内部参数名*](#local-parameter-name) [*类型注*](03_Types.md#type-annotation)
> >
> *参数* → [*外部参数名*](#external-parameter-name)<sub>可选</sub> [*内部参数名*](#local-parameter-name) [*类型注*](03_Types.md#type-annotation) **...** > *参数* → [*外部参数名*](#external-parameter-name)<sub>可选</sub> [*内部参数名*](#local-parameter-name) [*类型注*](03_Types.md#type-annotation) **...**
> >
> >
#### external-parameter-name {#external-parameter-name} #### external-parameter-name {#external-parameter-name}
@ -711,7 +697,6 @@ enum Number {
} }
// f 的类型为 (Int) -> Number // f 的类型为 (Int) -> Number
>
let f = Number.integer let f = Number.integer
// 利用 f 把一个整数数组转成 Number 数组 // 利用 f 把一个整数数组转成 Number 数组
@ -727,7 +712,6 @@ let evenInts: [Number] = [0, 2, 4, 6].map(f)
```swift ```swift
enum Tree<T> { enum Tree<T> {
>
case empty case empty
indirect case node(value: T, left: Tree, right:Tree) indirect case node(value: T, left: Tree, right:Tree)
} }
@ -1014,7 +998,7 @@ protocol 协议名称: 继承的协议 {
可以通过类型的扩展声明来采纳协议,从而为之前声明的类型添加协议一致性。在扩展中,必须实现所有采纳协议的要求。如果该类型已经实现了所有的要求,可以让这个扩展声明的主体留空。 可以通过类型的扩展声明来采纳协议,从而为之前声明的类型添加协议一致性。在扩展中,必须实现所有采纳协议的要求。如果该类型已经实现了所有的要求,可以让这个扩展声明的主体留空。
默认地,符合某个协议的类型必须实现所有在协议中声明的属性、方法和下标。即便如此,可以用 `optional` 声明修饰符标注协议成员声明,以指定它们的实现是可选的。`optional` 修饰符仅仅可以用于使用 `objc` 特性标记过的协议。因此,仅仅类类型可以采用并符合包含可选成员要求的协议。更多关于如何使用 `optional` 声明修饰符的信息,以及如何访问可选协议成员的指导——例如不能确定采纳协议的类型是否实现了它们时——请参阅 [可选协议要求](../chapter2/21_Protocols.md#optional_protocol_requirements) 默认地,符合某个协议的类型必须实现所有在协议中声明的属性、方法和下标。即便如此,可以用 `optional` 声明修饰符标注协议成员声明,以指定它们的实现是可选的。`optional` 修饰符仅仅可以用于使用 `objc` 特性标记过的协议。因此,仅仅类类型可以采用并符合包含可选成员要求的协议。更多关于如何使用 `optional` 声明修饰符的信息,以及如何访问可选协议成员的指导——例如不能确定采纳协议的类型是否实现了它们时——请参阅 [可选协议要求](../chapter2/21_Protocols.md#optional_protocol_requirements)
为了限制协议只能被类类型采纳,需要使用 `AnyObject` 关键字来标记协议,将 `AnyObject` 关键在写在冒号后面的继承的协议列表的首位。例如,下面的协议只能被类类型采纳: 为了限制协议只能被类类型采纳,需要使用 `AnyObject` 关键字来标记协议,将 `AnyObject` 关键在写在冒号后面的继承的协议列表的首位。例如,下面的协议只能被类类型采纳:
@ -1092,7 +1076,9 @@ var 属性名: 类型 { get set }
同其它协议成员声明一样,这些属性声明仅仅针对符合该协议的类型声明了 getter 和 setter 要求,你不能在协议中直接实现 getter 和 setter。 同其它协议成员声明一样,这些属性声明仅仅针对符合该协议的类型声明了 getter 和 setter 要求,你不能在协议中直接实现 getter 和 setter。
符合类型可以通过多种方式满足 getter 和 setter 要求。如果属性声明包含 `get``set` 关键字,符合类型就可以用存储型变量属性或可读可写的计算型属性来满足此要求,但是属性不能以常量属性或只读计算型属性实现。如果属性声明仅仅包含 `get` 关键字的话,它可以作为任意类型的属性被实现。关于如何实现协议中的属性要求的例子,请参阅 [属性要求](../chapter2/21_Protocols.md#property_requirements) 符合类型可以通过多种方式满足 getter 和 setter 要求。如果属性声明包含 `get``set` 关键字,符合类型就可以用存储型变量属性或可读可写的计算型属性来满足此要求,但是属性不能以常量属性或只读计算型属性实现。如果属性声明仅仅包含 `get` 关键字的话,它可以作为任意类型的属性被实现。关于如何实现协议中的属性要求的例子,请参阅 [属性要求](../chapter2/21_Protocols.md#property_requirements)
协议声明中声明一个类型属性,属性声明语句必须用 `static` 声明修饰符。当结构体和枚举遵循该协议时,使用 `static` 关键字修饰,而类遵循该协议时,使用 `static``class` 关键字皆可。当结构体,枚举或类添加扩展遵循协议时,和之前扩展用到的关键字保持一致。扩展为类属性提供默认实现时,必须使用 `static` 关键字修饰。
另请参阅 [变量声明](#variable_declaration)。 另请参阅 [变量声明](#variable_declaration)。
@ -1103,13 +1089,13 @@ var 属性名: 类型 { get set }
> >
#### protocol-property-declaration {#protocol-property-declaration} #### protocol-property-declaration {#protocol-property-declaration}
> >
> *协议属性声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型注*](03_Types.md#type-annotation) [*getter-setter 关键字代码块*](#getter-setter-keyword-block) > *协议属性声明* → [*变量声明头*](#variable-declaration-head) [*变量名称*](#variable-name) [*类型注*](03_Types.md#type-annotation) [*getter-setter 关键字代码块*](#getter-setter-keyword-block)
> >
### 协议方法声明 {#protocol-method-declaration} ### 协议方法声明 {#protocol-method-declaration}
协议可以通过在协议声明主体中引入一个协议方法声明,来声明符合的类型必须实现的方法。协议方法声明和函数方法声明有着相同的形式,但有两项例外:它们不包括函数体,也不能包含默认参数。关于如何实现协议中的方法要求的例子,请参阅 [方法要求](../chapter2/21_Protocols.md#method_requirements)。 协议可以通过在协议声明主体中引入一个协议方法声明,来声明符合的类型必须实现的方法。协议方法声明和函数方法声明有着相同的形式,但有两项例外:它们不包括函数体,也不能包含默认参数。关于如何实现协议中的方法要求的例子,请参阅 [方法要求](../chapter2/21_Protocols.md#method_requirements)。
使用 `static` 声明修饰符可以在协议声明中声明一个类型方法。类在实现这些方法时使用 `class` 声明修饰符。结构体实现这些方法时必须使用 `static` 声明修饰符。通过扩展实现时亦是如此(类的扩展中使用 `class` 声明修饰符,结构体的扩展中使用 `static` 声明修饰符) 协议声明中声明一个类型方法,方法声明语句必须用 `static` 声明修饰符。结构体和枚举遵循协议时,必须使用 `static` 关键字修饰,而类遵循协议时,使用 `static``class` 关键字皆可。当结构体,枚举或类添加扩展遵循协议时,和之前扩展用到的关键字保持一致。扩展为类方法提供默认实现时,必须使用 `static` 关键字修饰
另请参阅 [函数声明](#function_declaration)。 另请参阅 [函数声明](#function_declaration)。
@ -1150,11 +1136,12 @@ var 属性名: 类型 { get set }
```swift ```swift
subscript (参数列表) -> 返回类型 { get set } subscript (参数列表) -> 返回类型 { get set }
>
``` ```
下标声明只为符合类型声明了 getter 和 setter 要求。如果下标声明包含 `get``set` 关键字,符合类型也必须实现 getter 和 setter 子句。如果下标声明只包含 `get` 关键字,符合类型必须实现 getter 子句,可以选择是否实现 setter 子句。 下标声明只为符合类型声明了 getter 和 setter 要求。如果下标声明包含 `get``set` 关键字,符合类型也必须实现 getter 和 setter 子句。如果下标声明只包含 `get` 关键字,符合类型必须实现 getter 子句,可以选择是否实现 setter 子句。
协议声明中声明一个静态下标,下标声明语句必须用 `static` 声明修饰符。当结构体和枚举遵循该协议时,下标声明使用 `static` 关键字修饰,而类遵循该协议时,使用 `static``class` 关键字皆可。当结构体,枚举或类添加扩展遵循协议时,和之前扩展用到的关键字保持一致。扩展为下标声明提供默认实现时,必须使用 `static` 关键字修饰。
另请参阅 [下标声明](#subscript_declaration)。 另请参阅 [下标声明](#subscript_declaration)。
@ -1441,18 +1428,15 @@ doSomething(with: oneAndTwo)
```swift ```swift
protocol Serializable { protocol Serializable {
func serialize() -> Any func serialize() -> Any
>
} }
extension Array: Serializable where Element == Int { extension Array: Serializable where Element == Int {
func serialize() -> Any { func serialize() -> Any {
>
// implementation // implementation
} }
} }
extension Array: Serializable where Element == String { extension Array: Serializable where Element == String {
func serialize() -> Any { func serialize() -> Any {
>
// implementation // implementation
} }
} }
@ -1468,7 +1452,6 @@ extension String: SerializableInArray { }
extension Array: Serializable where Element: SerializableInArray { extension Array: Serializable where Element: SerializableInArray {
func serialize() -> Any { func serialize() -> Any {
>
// 具体实现 // 具体实现
} }
} }
@ -1536,7 +1519,6 @@ extension Array: Loggable where Element: MarkedLoggable { }
```swift ```swift
subscript (参数列表) -> 返回类型 { subscript (参数列表) -> 返回类型 {
>
get { get {
语句 语句
} }
@ -1548,20 +1530,25 @@ subscript (参数列表) -> 返回类型 {
下标声明只能出现在类、结构体、枚举、扩展和协议的声明中。 下标声明只能出现在类、结构体、枚举、扩展和协议的声明中。
参数列表指定一个或多个用于在相关类型的下标表达式中访问元素的索引(例如,表达式 `object[i]` 中的 `i`)。索引可以是任意类型,但是必须包含类型注。返回类型指定了被访问的元素的类型。 参数列表指定一个或多个用于在相关类型的下标表达式中访问元素的索引(例如,表达式 `object[i]` 中的 `i`)。索引可以是任意类型,但是必须包含类型注。返回类型指定了被访问的元素的类型。
和计算型属性一样下标声明支持对元素的读写操作。getter 用于读取值setter 用于写入值。setter 子句是可选的,当仅需要一个 getter 子句时,可以将二者都忽略,直接返回请求的值即可。但是,如果提供了 setter 子句,就必须提供 getter 子句。 和计算型属性一样下标声明支持对元素的读写操作。getter 用于读取值setter 用于写入值。setter 子句是可选的,当仅需要一个 getter 子句时,可以将二者都忽略,直接返回请求的值即可。但是,如果提供了 setter 子句,就必须提供 getter 子句。
圆括号以及其中的 setter 名称是可选的。如果提供了 setter 名称,它会作为 setter 的参数名称。如果不提供 setter 名称,那么 setter 的参数名称默认是 `value`。setter 名称的类型必须与返回类型相同。 圆括号以及其中的 setter 名称是可选的。如果提供了 setter 名称,它会作为 setter 的参数名称。如果不提供 setter 名称,那么 setter 的参数名称默认是 `value`。setter 的参数类型必须与返回类型相同。
可以重写下标,只要参数列表或返回类型不同即可。还可以重写继承自超类的下标,此时必须使用 `override` 声明修饰符声明被重写的下标。 可以重写下标,只要参数列表或返回类型不同即可。还可以重写继承自超类的下标,此时必须使用 `override` 声明修饰符声明被重写的下标。
默认情况下,下标中的参数不会含有 下标参数遵循与函数参数相同的规则,但有两个例外。默认情况下,下标中使用的参数不需要指定标签,这与函数,方法和构造器不同。但是你也可以同它们一样,显式地提供参数标签。此外,下标不能有 `In-out` 参数。
同样可以在协议声明中声明下标,正如 [协议下标声明](#protocol_subscript_declaration) 中所述。 同样可以在协议声明中声明下标,正如 [协议下标声明](#protocol_subscript_declaration) 中所述。
更多关于下标的信息和例子,请参阅 [下标](../chapter2/12_Subscripts.md)。 更多关于下标的信息和例子,请参阅 [下标](../chapter2/12_Subscripts.md)。
### 类型下标声明
声明一个由类型而不是类型实例公开的下标,请使用 `static` 声明修饰符标记下标声明。类可以使用 `class` 声明修饰符标记类型计算属性,以允许子类重写父类的实现。在类声明中,`static` 关键字具有与用 `class``final` 声明修饰符标记声明相同的效果。
#### grammer_of_a_subscript_declaration {#grammer-of-a-subscript-declaration} #### grammer_of_a_subscript_declaration {#grammer-of-a-subscript-declaration}
> 下标声明语法 > 下标声明语法
@ -1673,7 +1660,7 @@ precedencegroup 优先级组名称{
> 使用较低和较高优先级组相互联系的优先级组必须保持单一层次关系,但它们不必是线性关系。这意味着优先级组也许会有未定义的相关优先级。这些优先级组的运算符在没有用圆括号分组的情况下是不能紧邻着使用的。 > 使用较低和较高优先级组相互联系的优先级组必须保持单一层次关系,但它们不必是线性关系。这意味着优先级组也许会有未定义的相关优先级。这些优先级组的运算符在没有用圆括号分组的情况下是不能紧邻着使用的。
> >
Swift 定义了大量的优先级组来与标准库的运算符配合使用,例如相加(`+`)和相减(`-`)属于 `AdditionPrecedence` 组,相乘(`*`)和相除(`/`)属于 `MultiplicationPrecedence` 组,详细关于 Swift 标准库中一系列运算符和优先级组内容,参阅[Swift 标准库操作符参考](https://developer.apple.com/documentation/swift/operator_declarations)。 Swift 定义了大量的优先级组来与标准库的运算符配合使用,例如相加(`+`)和相减(`-`)属于 `AdditionPrecedence` 组,相乘(`*`)和相除(`/`)属于 `MultiplicationPrecedence` 组,详细关于 Swift 标准库中一系列运算符和优先级组内容,参阅 [Swift 标准库操作符参考](https://developer.apple.com/documentation/swift/operator_declarations)。
运算符的结合性表示在没有圆括号分组的情况下,同样优先级的一系列运算符是如何被分组的。你可以指定运算符的结合性通过上下文关键字 `left``right` 或者 `none`,如果没有指定结合性,默认是 `none` 关键字。左关联性的运算符是从左至右分组的,例如,相减操作符(-)是左关联性的,所以表达式 `4 - 5 - 6` 被分组为 `(4 - 5) - 6`,得出结果-7。右关联性的运算符是从右往左分组的指定为 `none` 结合性的运算符就没有结合性。同样优先级没有结合性的运算符不能相邻出现,例如 `<` 运算符是 `none` 结合性,那表示 `1 < 2 < 3` 就不是一个有效表达式。 运算符的结合性表示在没有圆括号分组的情况下,同样优先级的一系列运算符是如何被分组的。你可以指定运算符的结合性通过上下文关键字 `left``right` 或者 `none`,如果没有指定结合性,默认是 `none` 关键字。左关联性的运算符是从左至右分组的,例如,相减操作符(-)是左关联性的,所以表达式 `4 - 5 - 6` 被分组为 `(4 - 5) - 6`,得出结果-7。右关联性的运算符是从右往左分组的指定为 `none` 结合性的运算符就没有结合性。同样优先级没有结合性的运算符不能相邻出现,例如 `<` 运算符是 `none` 结合性,那表示 `1 < 2 < 3` 就不是一个有效表达式。
@ -1731,6 +1718,10 @@ Swift 定义了大量的优先级组来与标准库的运算符配合使用,
## 声明修饰符 {#Declaration-Modifiers} ## 声明修饰符 {#Declaration-Modifiers}
声明修饰符都是关键字或上下文相关的关键字,可以修改一个声明的行为或者含义。可以在声明的特性(如果存在)和引入该声明的关键字之间,利用声明修饰符的关键字或上下文相关的关键字指定一个声明修饰符。 声明修饰符都是关键字或上下文相关的关键字,可以修改一个声明的行为或者含义。可以在声明的特性(如果存在)和引入该声明的关键字之间,利用声明修饰符的关键字或上下文相关的关键字指定一个声明修饰符。
`class`
该修饰符用于修饰任何类成员,表明是类自身的成员,而不是类实例的成员。父类中使用该修饰符标记或者未被 `final` 修饰符标记的成员,都允许被子类重写。
`dynamic` `dynamic`
该修饰符用于修饰任何兼容 Objective-C 的类的成员。访问被 `dynamic` 修饰符标记的类成员将总是由 Objective-C 运行时系统进行动态派发,而不会由编译器进行内联或消虚拟化。 该修饰符用于修饰任何兼容 Objective-C 的类的成员。访问被 `dynamic` 修饰符标记的类成员将总是由 Objective-C 运行时系统进行动态派发,而不会由编译器进行内联或消虚拟化。
@ -1755,6 +1746,10 @@ Swift 定义了大量的优先级组来与标准库的运算符配合使用,
该修饰符用于修饰类的指定构造器或便利构造器,表示该类所有的子类都必须实现该构造器。在子类实现该构造器时,必须同样使用 `required` 修饰符修饰该构造器。 该修饰符用于修饰类的指定构造器或便利构造器,表示该类所有的子类都必须实现该构造器。在子类实现该构造器时,必须同样使用 `required` 修饰符修饰该构造器。
`static`
该修饰符用于修饰结构体、类、枚举或协议的成员,表明是类型成员,而不是类型实例的成员。在类声明的作用范围内,使用 `static` 修饰符标记成员声明语句,同 `class``final` 修饰符具有相同的效果。但是类的常量类型属性是一个例外: `static` 没有问题,但是你无法为常量声明使用 `class``final` 修饰符。
`unowned` `unowned`
该修饰符用于修饰存储型变量、常量或者存储型变量属性,表示该变量或属性持有其存储对象的无主引用。如果在此存储对象释放后尝试访问该对象,会引发运行时错误。如同弱引用一样,该引用类型的变量或属性必须是类类型。与弱引用不同的是,这种类型的变量或属性是非可选的。关于 `unowned` 更多的信息和例子,请参阅 [无主引用](../chapter2/23_Automatic_Reference_Counting.md#unowned_references) 该修饰符用于修饰存储型变量、常量或者存储型变量属性,表示该变量或属性持有其存储对象的无主引用。如果在此存储对象释放后尝试访问该对象,会引发运行时错误。如同弱引用一样,该引用类型的变量或属性必须是类类型。与弱引用不同的是,这种类型的变量或属性是非可选的。关于 `unowned` 更多的信息和例子,请参阅 [无主引用](../chapter2/23_Automatic_Reference_Counting.md#unowned_references)
@ -1765,7 +1760,7 @@ Swift 定义了大量的优先级组来与标准库的运算符配合使用,
`unowned(unsafe)` `unowned(unsafe)`
该修饰符用于修饰存储型变量、常量或者存储型变量属性,表示该变量或属性持有其存储对象的无主引用。如果在此存储对象释放后尝试访问该对象,会直接访问该对象释放前存储的内存地址,因此这是非内存安全的操作。如同弱引用一样,该引用类型的变量或属性必须是类类型。与弱引用不同的是,这种类型的变量或属性是非可选的。关于 `unowned` 更多的信息和例子,请参阅 [无主引用]( 该修饰符用于修饰存储型变量、常量或者存储型变量属性,表示该变量或属性持有其存储对象的无主引用。如果在此存储对象释放后尝试访问该对象,会直接访问该对象释放前存储的内存地址,因此这是非内存安全的操作。如同弱引用一样,该引用类型的变量或属性必须是类类型。与弱引用不同的是,这种类型的变量或属性是非可选的。关于 `unowned` 更多的信息和例子,请参阅 [无主引用](../chapter2/23_Automatic_Reference_Counting.md#resolving_strong_reference_cycles_between_class_instances)。
`weak` `weak`

View File

@ -151,7 +151,6 @@ dial.dynamicallyCall(withArguments: [4, 1, 1])
@dynamicCallable @dynamicCallable
struct Repeater { struct Repeater {
func dynamicallyCall(withKeywordArguments pairs: KeyValuePairs<String, Int>) -> String { func dynamicallyCall(withKeywordArguments pairs: KeyValuePairs<String, Int>) -> String {
>
return pairs return pairs
.map { label, count in .map { label, count in
repeatElement(label, count: count).joined(separator: " ") repeatElement(label, count: count).joined(separator: " ")
@ -183,7 +182,11 @@ repeatLabels(a: "four") // Error
该特性用于类、结构体、枚举或协议,让其能在运行时查找成员。该类型必须实现 `subscript(dynamicMemberLookup:)` 下标。 该特性用于类、结构体、枚举或协议,让其能在运行时查找成员。该类型必须实现 `subscript(dynamicMemberLookup:)` 下标。
在显式成员表达式中,如果没有成名指定成员,则该表达式被理解为对该类型的 `subscript(dynamicMemberLookup:)` 下标的调用,传递包含成员名称字符串的参数。下标的参数只需遵循 `ExpressibleByStringLiteral` 协议,返回值类型可以为任意类型。在大多数情况下,下标的参数是一个 `String` 值。例如: 在显式成员表达式中,如果没有成名指定成员,则该表达式被理解为对该类型的 `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 ```swift
@dynamicMemberLookup @dynamicMemberLookup
@ -191,7 +194,6 @@ struct DynamicStruct {
let dictionary = ["someDynamicMember": 325, let dictionary = ["someDynamicMember": 325,
"someOtherMember": 787] "someOtherMember": 787]
subscript(dynamicMember member: String) -> Int { subscript(dynamicMember member: String) -> Int {
>
return dictionary[member] ?? 1054 return dictionary[member] ?? 1054
} }
} }
@ -208,6 +210,24 @@ print(dynamic == equivalent)
// 打印“true” // 打印“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} ### `GKInspectable` {#gkinspectable}
应用此属性,暴露一个自定义 GameplayKit 组件属性给 SpriteKit 编辑器 UI。 应用此属性,暴露一个自定义 GameplayKit 组件属性给 SpriteKit 编辑器 UI。
@ -263,7 +283,7 @@ NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
- 父类有 `objc` 特性,且重写为子类的声明。 - 父类有 `objc` 特性,且重写为子类的声明。
- 遵循带有 `objc` 特性协议的声明。 - 遵循带有 `objc` 特性协议的声明。
- 带有 `IBAction``IBOutlet``IBDesignable``IBInspectable``NSManaged``GKInspectable` 特性的声明。 - 带有 `IBAction` `IBSegueAction``IBOutlet``IBDesignable``IBInspectable``NSManaged``GKInspectable` 特性的声明。
如果你将 `objc` 特性应用于枚举,每一个枚举用例都会以枚举名称和用例名称组合的方式暴露在 Objective-C 代码中。例如,在 `Planet` 枚举中有一个名为 `Venus` 的用例,该用例暴露在 Objective-C 代码中时叫做 `PlanetVenus` 如果你将 `objc` 特性应用于枚举,每一个枚举用例都会以枚举名称和用例名称组合的方式暴露在 Objective-C 代码中。例如,在 `Planet` 枚举中有一个名为 `Venus` 的用例,该用例暴露在 Objective-C 代码中时叫做 `PlanetVenus`
@ -315,11 +335,11 @@ class ExampleClass: NSObject {
### Interface Builder 使用的声明特性 {#declaration-attributes-used-by-interface-builder} ### Interface Builder 使用的声明特性 {#declaration-attributes-used-by-interface-builder}
`Interface Builder` 特性是 `Interface Builder` 用来与 Xcode 同步的声明特性。`Swift` 提供了以下的 `Interface Builder` 特性:`IBAction``IBOutlet``IBDesignable`,以及 `IBInspectable` 。这些特性与 Objective-C 中对应的特性在概念上是相同的。 `Interface Builder` 特性是 `Interface Builder` 用来与 Xcode 同步的声明特性。`Swift` 提供了以下的 `Interface Builder` 特性:`IBAction``IBSegueAction``IBOutlet``IBDesignable`,以及 `IBInspectable` 。这些特性与 Objective-C 中对应的特性在概念上是相同的。
`IBOutlet``IBInspectable` 用于修饰一个类的属性声明,`IBAction` 特性用于修饰一个类的方法声明,`IBDesignable` 用于修饰类的声明。 `IBOutlet``IBInspectable` 用于修饰一个类的属性声明,`IBAction` 特性用于修饰一个类的方法声明,`IBDesignable` 用于修饰类的声明。
应用 `IBAction``IBOutlet``IBDesignable` 或者 `IBInspectable` 特性都意味着同时应用 `objc` 特性。 应用 `IBAction``IBSegueAction``IBOutlet``IBDesignable` 或者 `IBInspectable` 特性都意味着同时应用 `objc` 特性。
## 类型特性 {#type-attributes} ## 类型特性 {#type-attributes}

View File

@ -4,7 +4,7 @@
Swift 中的模式分为两类:一种能成功匹配任何类型的值,另一种在运行时匹配某个特定值时可能会失败。 Swift 中的模式分为两类:一种能成功匹配任何类型的值,另一种在运行时匹配某个特定值时可能会失败。
第一类模式用于解构简单变量、常量和可选绑定中的值。此类模式包括通配符模式、标识符模式,以及包含前两种模式的值绑定模式和元组模式。你可以为这类模式指定一个类型注,从而限制它们只能匹配某种特定类型的值。 第一类模式用于解构简单变量、常量和可选绑定中的值。此类模式包括通配符模式、标识符模式,以及包含前两种模式的值绑定模式和元组模式。你可以为这类模式指定一个类型注,从而限制它们只能匹配某种特定类型的值。
第二类模式用于全模式匹配,这种情况下你试图匹配的值在运行时可能不存在。此类模式包括枚举用例模式、可选模式、表达式模式和类型转换模式。你在 `switch` 语句的 `case` 标签中,`do` 语句的 `catch` 子句中,或者在 `if``while``guard``for-in` 语句的 `case` 条件句中使用这类模式。 第二类模式用于全模式匹配,这种情况下你试图匹配的值在运行时可能不存在。此类模式包括枚举用例模式、可选模式、表达式模式和类型转换模式。你在 `switch` 语句的 `case` 标签中,`do` 语句的 `catch` 子句中,或者在 `if``while``guard``for-in` 语句的 `case` 条件句中使用这类模式。
@ -12,13 +12,13 @@ Swift 中的模式分为两类:一种能成功匹配任何类型的值,另
> >
#### pattern {#pattern} #### 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)
> >
@ -91,7 +91,7 @@ case let (x, y):
## 元组模式 {#tuple-pattern} ## 元组模式 {#tuple-pattern}
*元组模式*是由逗号分隔的,具有零个或多个模式的列表,并由一对圆括号括起来。元组模式匹配相应元组类型的值。 *元组模式*是由逗号分隔的,具有零个或多个模式的列表,并由一对圆括号括起来。元组模式匹配相应元组类型的值。
你可以使用类型注去限制一个元组模式能匹配哪种元组类型。例如,在常量声明 `let (x, y): (Int, Int) = (1, 2)` 中的元组模式 `(x, y): (Int, Int)` 只匹配两个元素都是 `Int` 类型的元组。 你可以使用类型注去限制一个元组模式能匹配哪种元组类型。例如,在常量声明 `let (x, y): (Int, Int) = (1, 2)` 中的元组模式 `(x, y): (Int, Int)` 只匹配两个元素都是 `Int` 类型的元组。
当元组模式被用于 `for-in` 语句或者变量和常量声明时,它仅可以包含通配符模式、标识符模式、可选模式或者其他包含这些模式的元组模式。比如下面这段代码就不正确,因为 `(x, 0)` 中的元素 `0` 是一个表达式模式: 当元组模式被用于 `for-in` 语句或者变量和常量声明时,它仅可以包含通配符模式、标识符模式、可选模式或者其他包含这些模式的元组模式。比如下面这段代码就不正确,因为 `(x, 0)` 中的元素 `0` 是一个表达式模式:
@ -228,7 +228,6 @@ default:
```swift ```swift
// 重载 ~= 运算符对字符串和整数进行比较 // 重载 ~= 运算符对字符串和整数进行比较
func ~=(pattern: String, value: Int) -> Bool { func ~=(pattern: String, value: Int) -> Bool {
>
return pattern == "\(value)" return pattern == "\(value)"
} }

View File

@ -21,7 +21,6 @@
```swift ```swift
func simpleMax<T: Comparable>(_ x: T, _ y: T) -> T { func simpleMax<T: Comparable>(_ x: T, _ y: T) -> T {
>
if x < y { if x < y {
return y return y
} }
@ -52,7 +51,7 @@ simpleMax(3.14159, 2.71828) // T 被推断为 Double 类型
泛型函数或构造器可以重载,但在泛型形参子句中的类型形参必须有不同的约束或要求,抑或二者皆不同。当调用重载的泛型函数或构造器时,编译器会根据这些约束来决定调用哪个重载函数或构造器。 泛型函数或构造器可以重载,但在泛型形参子句中的类型形参必须有不同的约束或要求,抑或二者皆不同。当调用重载的泛型函数或构造器时,编译器会根据这些约束来决定调用哪个重载函数或构造器。
更多关于泛型 where 从句的信息和关于泛型函数声明的例子,可以看一看 [泛型 where 子句](../chapter2/22_Generics.md#where_clauses) 更多关于泛型 where 从句的信息和关于泛型函数声明的例子,可以看一看 [泛型 where 子句](../chapter2/22_Generics.md#where_clauses)
> 泛型形参子句语法 > 泛型形参子句语法
> >
@ -117,7 +116,6 @@ struct Dictionary<Key: Hashable, Value>: CollectionType, DictionaryLiteralConver
```swift ```swift
let arrayOfArrays: Array<Array<Int>> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] let arrayOfArrays: Array<Array<Int>> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>
``` ```
如 [泛型形参子句](#generic_parameter) 所述,不能用泛型实参子句来指定泛型函数或构造器的类型实参。 如 [泛型形参子句](#generic_parameter) 所述,不能用泛型实参子句来指定泛型函数或构造器的类型实参。

View File

@ -1,6 +1,6 @@
# 文档翻译 & 校对工作记录 # 文档翻译 & 校对工作记录
Swift 官方文档中文翻译工作由[numbbbbb](https://github.com/numbbbbb)发起并主导,该工作已经得到了苹果官方的认可。下面是各个版本官方文档翻译和校对工作的主要贡献者,排名不分先后。 Swift 官方文档中文翻译由 [numbbbbb](https://github.com/numbbbbb) 发起并主导,本项目已经得到了苹果官方的 [认可](https://swift.org/documentation/)Translations 部分)。下面是各个版本官方文档翻译和校对工作的主要贡献者,排名不分先后。
## Swift 5.x 主要贡献者 ## Swift 5.x 主要贡献者
@ -12,11 +12,16 @@ Swift 官方文档中文翻译工作由[numbbbbb](https://github.com/numbbbbb)
- [DarrenChen123](https://github.com/DarrenChen123) - [DarrenChen123](https://github.com/DarrenChen123)
- [dzyding](https://github.com/dzyding) - [dzyding](https://github.com/dzyding)
- [Hale](https://github.com/wuqiuhao) - [Hale](https://github.com/wuqiuhao)
- [Joeytat](https://github.com/joeytat)
- [jojotov](https://github.com/jojotov) - [jojotov](https://github.com/jojotov)
- [Khala-wan](https://github.com/Khala-wan) - [Khala-wan](https://github.com/Khala-wan)
- [Nemocdz](https://github.com/Nemocdz) - [Nemocdz](https://github.com/Nemocdz)
- [numbbbbb](https://github.com/numbbbbb) - [numbbbbb](https://github.com/numbbbbb)
- [pmst](https://github.com/colourful987)
- [RickeyBoy](https://github.com/RickeyBoy)
- [SunsetWan](https://github.com/SunsetWan)
- [WAMaker](https://github.com/WAMaker) - [WAMaker](https://github.com/WAMaker)
- [YiYiZheng](https://github.com/YiYiZheng)
- [Yousanflics](https://github.com/Yousanflics) - [Yousanflics](https://github.com/Yousanflics)
## Swift 4.x 主要贡献者 ## Swift 4.x 主要贡献者
@ -143,4 +148,3 @@ Swift 官方文档中文翻译工作由[numbbbbb](https://github.com/numbbbbb)
- [zqp](https://github.com/zqp) - [zqp](https://github.com/zqp)
- [成都老码团队翻译组-Arya](http://weibo.com/littlekok/) - [成都老码团队翻译组-Arya](http://weibo.com/littlekok/)
- [成都老码团队翻译组-Oberyn](http://weibo.com/u/5241713117) - [成都老码团队翻译组-Oberyn](http://weibo.com/u/5241713117)