Compare commits
88 Commits
gitbook
...
numbbbbb-p
| Author | SHA1 | Date | |
|---|---|---|---|
| a064d9f4d6 | |||
| b7a8566a0f | |||
| ebda86cd05 | |||
| 546db6bc47 | |||
| 3d64a8e5e6 | |||
| b95202eb6d | |||
| ed7eb9e045 | |||
| 15ee26ca6d | |||
| dca10b1aa0 | |||
| 2d10a8d6ec | |||
| a6d6e468f6 | |||
| 72708963ab | |||
| 22265fa31d | |||
| 771c5b3da0 | |||
| 0369884f87 | |||
| 75e0837fb0 | |||
| 0afcd2ebf1 | |||
| d07fdbfb98 | |||
| 21e80f09b5 | |||
| 2b140081de | |||
| 60cc810915 | |||
| 68e51d7f57 | |||
| 4381756f0f | |||
| 96f3c84b8a | |||
| cc029194be | |||
| ae117bdfbc | |||
| 5fc4252bfc | |||
| 9ec61ba488 | |||
| fc89e3ca5d | |||
| 9a629a57e3 | |||
| 787687cb1e | |||
| b699654ab8 | |||
| d902be8367 | |||
| d90c50ec74 | |||
| 4894951c3b | |||
| b5defb4c0e | |||
| b1887d01ac | |||
| 5f0da139f0 | |||
| 53eaaeb19c | |||
| c9c9bb980e | |||
| 51ceab425c | |||
| 16cae8adf6 | |||
| bab43e7db6 | |||
| 4cace74528 | |||
| b807a6edb9 | |||
| 1a6d56d228 | |||
| 004fc0906d | |||
| 850cf97f83 | |||
| d6862fa4dc | |||
| d3efb989d3 | |||
| 0f2ab87dca | |||
| 9a6f016f45 | |||
| 2164db3b8b | |||
| fb2dfa6764 | |||
| d8068f4325 | |||
| 4e4e291956 | |||
| 2f430495d4 | |||
| 7b123505db | |||
| e7def896cb | |||
| 5fbfc38fd7 | |||
| b26f8aacff | |||
| b76f8cf111 | |||
| ca87420665 | |||
| 93c390dd5a | |||
| 7020682acd | |||
| aa91ad4692 | |||
| 367cece0f5 | |||
| 3f0cc6c047 | |||
| 65dc6b133f | |||
| b58d744852 | |||
| e9aaa026c6 | |||
| 1167a215c9 | |||
| f5c9d9c5e5 | |||
| 71f0757ba0 | |||
| afc8cddb0e | |||
| a3a7770b9a | |||
| 1ffeeeedaf | |||
| b991a4eb75 | |||
| e3c9bd7992 | |||
| 425d534e7f | |||
| e0af10bc8e | |||
| 3210e30972 | |||
| e82cea3866 | |||
| 497d68be37 | |||
| cb2ebd282b | |||
| 9fd540b8d7 | |||
| 86690d4472 | |||
| de559ce2d8 |
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal 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']
|
||||
57
README.md
57
README.md
@ -5,19 +5,19 @@
|
||||
|
||||
[英文原版在线版](https://docs.swift.org/swift-book/)
|
||||
|
||||
[英文原版ePub版](https://docs.swift.org/swift-book/TheSwiftProgrammingLanguageSwift5.epub)
|
||||
|
||||
# 在线阅读
|
||||
|
||||
使用 GitBook 制作,可以直接 [在线阅读](https://swiftgg.gitbook.io/swift/)。
|
||||
|
||||
# 当前阶段
|
||||
|
||||
- 更新到 Swift 5.1,2019-07-10
|
||||
- 更新到 Swift 5.0,2019-04-05
|
||||
- 更新到 Swift 4.2,2019-01-29
|
||||
- 更新到 Swift 4.1,2018-04-12,感谢 [@Mylittleswift](https://github.com/Mylittleswift)
|
||||
- 更新到 Swift 3.0,2016-09-23
|
||||
|
||||
|
||||
# 贡献力量
|
||||
|
||||
如果想做出贡献的话,你可以:
|
||||
@ -62,19 +62,19 @@ diff 操作如下:
|
||||
| associated type | 关联类型 |
|
||||
| range | 区间 |
|
||||
| type property | 类型属性 |
|
||||
| Unary operator | 一元运算符 |
|
||||
| Binary operator | 二元运算符 |
|
||||
| Ternary operator | 三元运算符 |
|
||||
| Labeled Statement | 具名语句 |
|
||||
| conform Protocol | 遵循协议 |
|
||||
| unary operator | 一元运算符 |
|
||||
| binary operator | 二元运算符 |
|
||||
| ternary operator | 三元运算符 |
|
||||
| labeled statement | 具名语句 |
|
||||
| conform protocol | 遵循协议 |
|
||||
| availability-condition | 可用性条件 |
|
||||
| fallthrough | 贯穿 |
|
||||
| Branch Statement | 分支语句 |
|
||||
| Control Transfer Statement | 控制传递语句 |
|
||||
| Type Annotation | 类型标注 |
|
||||
| Type Identifier | 类型标识符 |
|
||||
| Metatype Type | 元类型 |
|
||||
| Protocol Composition Type | 复合协议类型 |
|
||||
| branch statement | 分支语句 |
|
||||
| control transfer statement | 控制传递语句 |
|
||||
| type annotation | 类型注解 |
|
||||
| type identifier | 类型标识符 |
|
||||
| metatype type | 元类型 |
|
||||
| protocol composition type | 复合协议类型 |
|
||||
| associated value | 关联值 |
|
||||
| raw value | 原始值 |
|
||||
| computed property | 计算属性 |
|
||||
@ -87,21 +87,21 @@ diff 操作如下:
|
||||
| statement | 语句 |
|
||||
| expression | 表达式 |
|
||||
| optional | 可选 |
|
||||
| Implicitly Unwrapped optional | 隐式解包可选值 |
|
||||
| Optional Binding | 可选绑定 |
|
||||
| implicitly unwrapped optional | 隐式解包可选值 |
|
||||
| optional binding | 可选绑定 |
|
||||
| optional chaining | 可选链 |
|
||||
| collection | 集合 |
|
||||
| convention | 约定 |
|
||||
| iterate | 迭代 |
|
||||
| nest | 嵌套 |
|
||||
| Inheritance | 继承 |
|
||||
| inheritance | 继承 |
|
||||
| override | 重写 |
|
||||
| base class | 基类 |
|
||||
| Designated Initializer | 指定构造器 |
|
||||
| Convenience Initializer | 便利构造器 |
|
||||
| Automatic Reference Counting | 自动引用计数 |
|
||||
| designated initializer | 指定构造器 |
|
||||
| convenience initializer | 便利构造器 |
|
||||
| automatic reference counting | 自动引用计数 |
|
||||
| type inference | 类型推断 |
|
||||
| Type Casting | 类型转换 |
|
||||
| type casting | 类型转换 |
|
||||
| unwrapped | 解包 |
|
||||
| wrapped | 包装 |
|
||||
| note | 注意 |
|
||||
@ -109,7 +109,7 @@ diff 操作如下:
|
||||
| tuple | 元组 |
|
||||
| first-class | 一等 |
|
||||
| deinitializer | 析构器 |
|
||||
| Initializer | 构造器 |
|
||||
| initializer | 构造器 |
|
||||
| initialization | 构造过程 |
|
||||
| deinitialization | 析构过程 |
|
||||
| getter | 不翻译 |
|
||||
@ -118,15 +118,18 @@ diff 操作如下:
|
||||
| property | 属性 |
|
||||
| attribute | 特性或者属性,根据上下文 |
|
||||
| method | 方法 |
|
||||
| Enumeration | 枚举 |
|
||||
| Structure | 结构体 |
|
||||
| Protocol | 协议 |
|
||||
| Extension | 扩展 |
|
||||
| Generic | 泛型 |
|
||||
| enumeration | 枚举 |
|
||||
| structure | 结构体 |
|
||||
| protocol | 协议 |
|
||||
| extension | 扩展 |
|
||||
| generic | 泛型 |
|
||||
| literal value | 字面量 |
|
||||
| alias | 别名 |
|
||||
| Assertion | 断言 |
|
||||
| assertion | 断言 |
|
||||
| conditional compilation | 条件编译 |
|
||||
| opaque type | 不透明类型 |
|
||||
| function | 函数 |
|
||||
| runtime | 运行时 |
|
||||
|
||||
# 贡献者
|
||||
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
# Summary
|
||||
|
||||
* [Introduction](README.md)
|
||||
|
||||
@ -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())
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
BIN
document/TheSwiftProgrammingLanguageSwift51.epub
Normal file
BIN
document/TheSwiftProgrammingLanguageSwift51.epub
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
google-site-verification: googleb0a4f5a22e9cb82f.html
|
||||
13
index.html
13
index.html
@ -1,19 +1,8 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-US" manifest="./manifest.appcache">
|
||||
|
||||
<head>
|
||||
|
||||
<meta http-equiv="refresh" content="0; url=http://wiki.jikexueyuan.com/project/swift/" />
|
||||
|
||||
|
||||
|
||||
<meta http-equiv="refresh" content="0; url=https://swiftgg.gitbook.io/swift/" />
|
||||
</head>
|
||||
<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>
|
||||
|
||||
</html>
|
||||
|
||||
4
source/.gitignore
vendored
4
source/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
_book
|
||||
*.pdf
|
||||
*.epub
|
||||
*.mobi
|
||||
165
source/README.md
165
source/README.md
@ -1,149 +1,22 @@
|
||||
# 文档翻译 & 校对工作记录
|
||||
|
||||
Swift 官方文档中文翻译工作由[numbbbbb](https://github.com/numbbbbb)发起并主导,该工作已经得到了苹果官方的认可。下面是各个版本官方文档翻译和校对工作的主要贡献者,排名不分先后。
|
||||
|
||||
## Swift 5.x 主要贡献者
|
||||
|
||||
- [Adolf-L](https://github.com/Adolf-L)
|
||||
- [BigNerdCoding](https://github.com/bignerdcoding)
|
||||
- [bqlin](https://github.com/bqlin)
|
||||
- [Byelaney](https://github.com/Byelaney)
|
||||
- [CMB](https://github.com/chenmingbiao)
|
||||
- [DarrenChen123](https://github.com/DarrenChen123)
|
||||
- [dzyding](https://github.com/dzyding)
|
||||
- [Hale](https://github.com/wuqiuhao)
|
||||
- [jojotov](https://github.com/jojotov)
|
||||
- [Khala-wan](https://github.com/Khala-wan)
|
||||
- [Nemocdz](https://github.com/Nemocdz)
|
||||
- [numbbbbb](https://github.com/numbbbbb)
|
||||
- [WAMaker](https://github.com/WAMaker)
|
||||
- [Yousanflics](https://github.com/Yousanflics)
|
||||
|
||||
## Swift 4.x 主要贡献者
|
||||
|
||||
- [Adolf-L](https://github.com/Adolf-L)
|
||||
- [BigNerdCoding](https://github.com/bignerdcoding)
|
||||
- [bqlin](https://github.com/bqlin)
|
||||
- [Cee](https://github.com/Cee)
|
||||
- [CMB](https://github.com/chenmingbiao)
|
||||
- [Damonwong](https://github.com/Damonvvong)
|
||||
- [Desgard](https://github.com/Desgard)
|
||||
- [dzyding](https://github.com/dzyding)
|
||||
- [EyreFree](https://www.eyrefree.org/)
|
||||
- [Forelas](https://github.com/ForelaxX)
|
||||
- [Hale](https://github.com/wuqiuhao)
|
||||
- [kemchenj](https://kemchenj.github.io)
|
||||
- [jojotov](https://github.com/jojotov)
|
||||
- [Meler](https://github.com/pmtao)
|
||||
- [mobilefellow](https://github.com/mobilefellow)
|
||||
- [muhlenXi](https://github.com/muhlenxi)
|
||||
- [mylittleswift](https://github.com/mylittleswift)
|
||||
- [Nemocdz](https://github.com/Nemocdz)
|
||||
- [numbbbbb](https://github.com/numbbbbb)
|
||||
- [rain2540](https://github.com/rain2540)
|
||||
- [Rsenjoyer](https://github.com/Rsenjoyer)
|
||||
- [WAMaker](https://github.com/WAMaker)
|
||||
- [YiYiZheng](https://github.com/YiYiZheng)
|
||||
- [ZhangChi](https://github.com/zhangchi25806)
|
||||
|
||||
## Swift 3.x 主要贡献者
|
||||
|
||||
- [bqlin](https://github.com/bqlin)
|
||||
- [chenmingjia](https://github.com/chenmingjia)
|
||||
- [CMB](https://github.com/chenmingbiao)
|
||||
- [crayygy](https://github.com/crayygy)
|
||||
- [kemchenj](https://kemchenj.github.io)
|
||||
- [Lanford](https://github.com/LanfordCai)
|
||||
- [mmoaay](https://github.com/mmoaay)
|
||||
- [mylittleswift](https://github.com/mylittleswift)
|
||||
- [qhd](https://github.com/qhd)
|
||||
- [shanks](https://github.com/shanksyang)
|
||||
|
||||
## Swift 2.x 主要贡献者
|
||||
|
||||
- [100mango](https://github.com/100mango)
|
||||
- [175](https://github.com/Brian175)
|
||||
- [BridgeQ](https://github.com/WXGBridgeQ)
|
||||
- [buginux](https://github.com/buginux)
|
||||
- [Cee](https://github.com/Cee)
|
||||
- [Channe](https://github.com/Channe)
|
||||
- [CMB](https://github.com/chenmingbiao)
|
||||
- [DianQK](https://github.com/DianQK)
|
||||
- [dreamkidd](https://github.com/dreamkidd)
|
||||
- [EudeMorgen](https://github.com/EudeMorgen)
|
||||
- [futantan](https://github.com/futantan)
|
||||
- [JackAlan](https://github.com/AlanMelody)
|
||||
- [KYawn](https://github.com/KYawn)
|
||||
- [Lanford](https://github.com/LanfordCai)
|
||||
- [Lenhoon](https://github.com/Lenhoon)
|
||||
- [littledogboy](https://github.com/littledogboy)
|
||||
- [LinusLing](https://github.com/linusling)
|
||||
- [lyojo](https://github.com/lyojo)
|
||||
- [miaosiqi](https://github.com/miaosiqi)
|
||||
- [mmoaay](https://github.com/mmoaay)
|
||||
- [overtrue](https://github.com/overtrue)
|
||||
- [pmst](https://github.com/colourful987)
|
||||
- [Prayer](https://github.com/futantan)
|
||||
- [qhd](https://github.com/qhd)
|
||||
- [ray16897188](https://github.com/ray16897188)
|
||||
- [Realank](https://github.com/realank)
|
||||
- [saitjr](https://github.com/saitjr)
|
||||
- [SergioChan](https://github.com/SergioChan)
|
||||
- [shanks](https://github.com/shanksyang)
|
||||
- [SketchK](https://github.com/SketchK)
|
||||
- [SkyJean](https://github.com/SkyJean)
|
||||
- [wardenNScaiyi](https:github.com/wardenNScaiyi)
|
||||
- [xtymichael](https://github.com/xtymichael)
|
||||
- [yangsiy](https://github.com/yangsiy)
|
||||
- [星夜暮晨](https://github.com/semperidem)
|
||||
- [小铁匠 Linus](https://github.com/kevin833752)
|
||||
|
||||
## Swift 1.x 主要贡献者
|
||||
|
||||
- [bruce0505](https://github.com/bruce0505)
|
||||
- [changkun](http://changkun.us/about/)
|
||||
- [ChildhoodAndy](http://childhood.logdown.com)
|
||||
- [coverxit](https://github.com/coverxit)
|
||||
- [dabing1022](https://github.com/dabing1022)
|
||||
- [EvilCome](https://github.com/Evilcome)
|
||||
- [feiin](https://github.com/feiin)
|
||||
- [fd5788](https://github.com/fd5788)
|
||||
- [geek5nan](https://github.com/geek5nan)
|
||||
- [happyming](https://github.com/happyming)
|
||||
- [Hawstein](https://github.com/Hawstein)
|
||||
- [honghaoz](https://github.com/honghaoz)
|
||||
- [JaceFu](http://www.devtalking.com/)
|
||||
- [Jasonbroker](https://github.com/Jasonbroker)
|
||||
- [JaySurplus](https://github.com/JaySurplus)
|
||||
- [Lenhoon](https://github.com/marsprince)
|
||||
- [lifedim](https://github.com/lifedim)
|
||||
- [Lin-H](https://github.com/Lin-H)
|
||||
- [lslxdx](https://github.com/lslxdx)
|
||||
- [LunaticM](https://github.com/LunaticM)
|
||||
- [lyuka](https://github.com/lyuka)
|
||||
- [marsprince](https://github.com/marsprince)
|
||||
- [menlongsheng](https://github.com/menlongsheng)
|
||||
- [NicePiao](https://github.com/NicePiao)
|
||||
- [numbbbbb](https://github.com/numbbbbb)
|
||||
- [pp-prog](https://github.com/pp-prog)
|
||||
- [sg552](https://github.com/sg552)
|
||||
- [stanzhai](https://github.com/stanzhai)
|
||||
- [shinyzhu](https://github.com/shinyzhu)
|
||||
- [superkam](https://github.com/superkam)
|
||||
- [takalard](https://github.com/takalard)
|
||||
- [TimothyYe](https://github.com/TimothyYe)
|
||||
- [vclwei](https://github.com/vclwei)
|
||||
- [wh1100717](https://github.com/wh1100717)
|
||||
- [xiehurricane](https://github.com/xiehurricane)
|
||||
- [XieLingWang](https://github.com/xielingwang)
|
||||
- [yangsiy](https://github.com/yangsiy)
|
||||
- [yankuangshi](https://github.com/yankuangshi)
|
||||
- [yeahdongcn](https://github.com/yeahdongcn)
|
||||
- [yangsiy](https://github.com/yangsiy)
|
||||
- [zqp](https://github.com/zqp)
|
||||
- [成都老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
||||
- [成都老码团队翻译组-Oberyn](http://weibo.com/u/5241713117)
|
||||
|
||||
> 2016.9.23: 已经更新到 Swift 3.0。
|
||||
# 3.0 更新说明
|
||||
Swift 3.0 是自 Swift 开源以来第一个大的版本更新。从语言角度不兼容之前的 Swift 2.2 和 Swift 2.3 版本。Swift 3.0 的更新说明,大家可以查看[官方 blog 的说明](https://swift.org/blog/swift-3-0-released/),也可以关注 [SwiftGG](http://swift.gg) 最新的文章。学习官方文档,是掌握语言特性点的最佳途径,感谢翻译的小伙伴们为 Swift 社区所做贡献!
|
||||
|
||||
# 3.0 译者记录
|
||||
相关[issue](https://github.com/numbbbbb/the-swift-programming-language-in-chinese/issues/628)
|
||||
- Functions: [crayygy](https://github.com/crayygy)
|
||||
- Control Flow: [Realank](https://github.com/Realank)
|
||||
- Closures: [LanfordCai](https://github.com/LanfordCai)
|
||||
- Protocols: [chenmingbiao](https://github.com/chenmingbiao)
|
||||
- The Basics:[chenmingbiao](https://github.com/chenmingbiao)
|
||||
- Advanced Operators: [mmoaay](https://github.com/mmoaay)
|
||||
|
||||
Language Reference:
|
||||
- Attributes: [WhoJave](https://github.com/WhoJave)
|
||||
- Statements: [chenmingjia](https://github.com/chenmingjia)
|
||||
- Declarations: [chenmingjia](https://github.com/chenmingjia)
|
||||
- Expressions: [chenmingjia](https://github.com/chenmingjia)
|
||||
- Types: [lettleprince](https://github.com/lettleprince)
|
||||
- Generic Parameters and Arguments: [chenmingjia](https://github.com/chenmingjia)
|
||||
|
||||
感谢阅读!
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
# Summary
|
||||
|
||||
* [Introduction](README.md)
|
||||
* 欢迎使用 Swift
|
||||
* [关于 Swift](chapter1/01_about_swift.md)
|
||||
* [版本兼容性](chapter1/02_version_compatibility.md)
|
||||
@ -29,6 +28,7 @@
|
||||
* [扩展](chapter2/20_Extensions.md)
|
||||
* [协议](chapter2/21_Protocols.md)
|
||||
* [泛型](chapter2/22_Generics.md)
|
||||
* [不透明类型](chapter2/27_Opaque_Types.md)
|
||||
* [自动引用计数](chapter2/23_Automatic_Reference_Counting.md)
|
||||
* [内存安全](chapter2/24_Memory_Safety.md)
|
||||
* [访问控制](chapter2/25_Access_Control.md)
|
||||
@ -46,4 +46,3 @@
|
||||
* [语法总结](chapter3/10_Summary_of_the_Grammar.md)
|
||||
* 翻译贡献者
|
||||
* [翻译贡献者](contributors.md)
|
||||
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
# 版本兼容性
|
||||
|
||||
本书描述的是在 Xcode 10.2 中的默认 Swift 版本 Swift 5。你可以使用 Xcode10.2 来构建 Swift 5、Swift 4.2 或 Swift 4 写的项目
|
||||
本书描述的是在 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?** 表达式不会为已返回可选类型的代码引入额外的可选类型层级。
|
||||
* 大数字的整型字面量初始化代码的类型将会被正确推导,例如 **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。
|
||||
|
||||
@ -65,7 +65,7 @@ let fruitSummary = "I have \(apples + oranges) pieces of fruit."
|
||||
>
|
||||
> 使用 `\()` 来把一个浮点计算转换成字符串,并加上某人的名字,和他打个招呼。
|
||||
|
||||
使用一对三个单引号(`"""`)来包含多行字符串内容,字符串中的内容(包括引号、空格、换行符等)都会保留下来。举个例子:
|
||||
使用三个双引号(`"""`)来包含多行字符串内容,字符串中的内容(包括引号、空格、换行符等)都会保留下来。举个例子:
|
||||
|
||||
```swift
|
||||
let quotation = """
|
||||
|
||||
@ -1,256 +1,267 @@
|
||||
# Swift 文档修订历史
|
||||
|
||||
### 2019-01-24
|
||||
### 2019-06-03
|
||||
|
||||
* 更新到 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)章节新增了小于比较符 `<` 相关内容。
|
||||
* 更新至 Swift 5.1。
|
||||
* 在 [不透明类型](../chapter2/27_Opaque_Types.md) 篇章中新增了有关函数返回值遵循指定协议,而不需要提供指定返回类型的内容。
|
||||
* 新增 [隐式返回的函数](../chapter2/06_Functions.md#functions-with-an-implicit-return) 和 [简化 Getter 声明](../chapter2/10_Properties.md#shorthand-getter-declaration) 章节,其中包含函数省略 `return` 的内容。
|
||||
* 在 [类型下标](../chapter2/12_Subscripts.md#type-subscripts) 章节中新增有关在类型中使用下标的内容。
|
||||
* 更新 [结构体的逐一成员构造器](../chapter2/14_Initialization.md#memberwise-initializers-for-structure-types) 章节,现在逐一成员构造器支持在属性有默认值时省略形参。
|
||||
* 在 [动态查找成员](../chapter3/07_Attributes.md#dynamicmemberlookup) 章节中新增了有关在运行时用 key path 查找动态成员的内容。
|
||||
* 更新 [自身类型](../chapter3/03_Types.md#self-type-h) 章节,现在 `Self` 可以指向当前类,结构体或者枚举声明时的类型。
|
||||
|
||||
### 2019-03-25
|
||||
|
||||
* 更新至 Swift 5。
|
||||
* 新增 [拓展字符串分隔符](../chapter2/03_Strings_And_Characters.md#extended-string-delimiters) 章节。更新 [字符串字面量](../chapter3/03_Lexical_Structure.md#string-literal) 章节,拓展有关字符串分隔符的内容。
|
||||
* 新增 [动态调用](../chapter3/07_Attributes.md#dynamiccallable) 章节,其中包含使用 `dynamicCallable` 属性动态调用实例作为函数的内容。
|
||||
* 新增 [unknown](../chapter3/07_Attributes.md#unknown) 和 [未来枚举匹配](../chapter3/05_Statements.md#future-case2) 章节,其中包含了使用 `unknown` 来处理未来枚举可能发生改变的情形。
|
||||
* 在 [Key-Path 表达式](../chapter3/04_Expressions.md#key-path-expression) 章节新增了有关标示 key path (\\.self) 的内容。
|
||||
* 在 [可选编译块](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节新增了有关小于比较符 `<` 的内容。
|
||||
|
||||
### 2018-09-17
|
||||
|
||||
* 更新至 Swift 4.2。
|
||||
* 在[遍历枚举情形](../chapter2/08_Enumerations.md#iterating-over-enumeration-cases)章节添加了访问所有枚举情形的内容。
|
||||
* 在[编译诊断](../chapter3/05_Statements.md#compile-time-diagnostic-statement)章节添加了有关 `#error` 和 `#warning` 相关内容。
|
||||
* 在[属性声明](../chapter3/07_Attributes.md#Ideclaration-attributes)章节中补充了 `inlinable` 和 `usableFromInline` 属性相关的内联信息。
|
||||
* 在[属性声明](../chapter3/07_Attributes.md#Ideclaration-attributes)章节中添加了 `requires_stored_property_inits` 和 `warn_unqualified_access` 属性相关的信息。
|
||||
* 在[可选编译块](../chapter3/05_Statements.md#Conditional-Compilation-Block)章节新增了如何根据 Swift 编译器版本对代码进行对应编译处理的内容。
|
||||
* 在[字面量语法](../chapter3/04_Expressions.md#literal-expression)章节补充了 `#dsohandle` 相关内容。
|
||||
* 在 [遍历枚举情形](../chapter2/08_Enumerations.md#iterating-over-enumeration-cases) 章节新增了有关访问所有枚举情形的内容。
|
||||
* 在 [编译诊断](../chapter3/05_Statements.md#compile-time-diagnostic-statement) 章节新增了有关 `#error` 和 `#warning` 的内容。
|
||||
* 在 [属性声明](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `inlinable` 和 `usableFromInline` 属性的内容。
|
||||
* 在 [属性声明](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `requires_stored_property_inits` 和 `warn_unqualified_access` 属性的内容。
|
||||
* 在 [可选编译块](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节新增了有关如何根据 Swift 编译器版本对代码进行对应编译处理的内容。
|
||||
* 在 [字面量语法](../chapter3/04_Expressions.md#literal-expression) 章节新增了有关 `#dsohandle` 的内容。
|
||||
|
||||
### 2018-03-29
|
||||
|
||||
* 更新至 Swift 4.1。
|
||||
* 在[等价运算符](../chapter2/26_Advanced_Operators.md#equivalence-operators)章节添加了等价运算符的合成实现信息。
|
||||
* 在[声明](../chapter3/06_Declarations.md)一章的[申明拓展](../chapter3/06_Declarations.md#extension-declaration)部分和[协议](../chapter2/21_Protocols.md)一章的[有条件地遵循协议](../chapter2/21_Protocols.md#Conditionally-Conforming-to-a-Protocol)部分添加了协议的有条件遵循相关内容。
|
||||
* 在[关联类型约束中使用协议](../chapter2/22_Generics.md##using-a-protocol-in-its-associated-type’s-constraints)章节中添加了递归协议约束的内容。
|
||||
* 在[条件编译块](../chapter3/05_Statements.md#Conditional-Compilation-Block)章节中添加了 `canImport()` 和 `targetEnvironment()` 平台条件相关内容。
|
||||
* 在 [等价运算符](../chapter2/26_Advanced_Operators.md#equivalence-operators) 章节新增了有关等价运算符的合成实现的内容。
|
||||
* 在 [声明](../chapter3/06_Declarations.md) 篇章中 [申明拓展](../chapter3/06_Declarations.md#extension-declaration) 章节和 [协议](../chapter2/21_Protocols.md) 篇章中 [有条件地遵循协议](../chapter2/21_Protocols.md#Conditionally-Conforming-to-a-Protocol) 章节新增了有关协议有条件遵循的内容。
|
||||
* 在 [关联类型约束中使用协议](../chapter2/22_Generics.md#using-a-protocol-in-its-associated-types-constraints) 章节中新增了有关递归协议约束的内容。
|
||||
* 在 [条件编译块](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节中新增了有关 `canImport()` 和 `targetEnvironment()` 平台条件的内容。
|
||||
|
||||
### 2017-12-04
|
||||
|
||||
* 更新至 Swift 4.0.3。
|
||||
* 更新[Key-Path](../chapter3/04_Expressions.md#key-path-expression)表达式章节,现在 key path 支持下标子路径。
|
||||
* 更新 [Key-Path 表达式](../chapter3/04_Expressions.md#key-path-expression) 章节,现在 key path 支持下标子路径。
|
||||
|
||||
### 2017-09-19
|
||||
|
||||
* 更新至 Swift 4.0。
|
||||
* 在[内存安全](../chapter2/24_MemorySafety.md)章节补充了内存互斥访问相关的内容。
|
||||
* 添加了[带有泛型 Where 子句联类型](../chapter2/22_Generics.md#associated-types-with-a-generic-where-clause)章节,现在可以使用泛型 `where` 子句约束关联类型。
|
||||
* 在[字符串和字符](../chapter2/03_Strings_And_Characters.md)的[字面量](../chapter2/03_Strings_And_Characters.md#string-literals)一节以及[词法结构](../chapter3/02_Lexical_Structure.md)的[字符串字面量](../chapter3/02_Lexical_Structure.md#string-literal)一节中新增了多行字符串字面量相关内容。
|
||||
* 更新了[声明属性](../chapter3/07_Attributes.md#Ideclaration-attributes)中 `objc` 属性的讨论,现在该属性是在更少的位置推断出来的。
|
||||
* 添加了[范型下标](../chapter2/22_Generics.md#generic-subscripts)章节,现在下标也支持范型特性了。
|
||||
* 更新了[协议](../chapter2/21_Protocols.md)一章中[协议组合](../chapter2/21_Protocols.md#protocol-composition)部分以及[类型](../chapter3/03_Types.md)一章中[协议组合类型](../chapter3/03_Types.md#protocol-composition)部分的讨论,现在协议组合类型支持进行父类约束了。
|
||||
* 更新了[拓展声明](../chapter3/06_Declarations.md#extension-declaration)中关于协议的讨论,现在它们不支持 `final` 特性了。
|
||||
* 在[断言和前置条件](../chapter2/01_TheBasics.md#assertions-and-preconditions)部分增加了部分前置条件和致命错误的内容。
|
||||
* 在 [内存安全](../chapter2/24_MemorySafety.md) 章节新增了有关内存互斥访问的内容。
|
||||
* 新增 [带有泛型 Where 子句联类型](../chapter2/22_Generics.md#associated-types-with-a-generic-where-clause) 章节,现在可以使用泛型 `where` 子句约束关联类型。
|
||||
* 在 [字符串和字符](../chapter2/03_Strings_And_Characters.md) 篇章中 [字面量](../chapter2/03_Strings_And_Characters.md#string-literals) 章节以及 [词法结构](../chapter3/02_Lexical_Structure.md) 篇章的 [字符串字面量](../chapter3/02_Lexical_Structure.md#string-literal) 章节中新增了有关多行字符串字面量的内容。
|
||||
* 更新 [声明属性](../chapter3/07_Attributes.md#Ideclaration-attributes) 中 `objc` 属性的讨论,现在该属性会在更少的位置被推断出来。
|
||||
* 新增 [范型下标](../chapter2/22_Generics.md#generic-subscripts) 章节,现在下标也支持范型特性了。
|
||||
* 更新 [协议](../chapter2/21_Protocols.md) 篇章中 [协议组合](../chapter2/21_Protocols.md#protocol-composition) 章节和 [类型](../chapter3/03_Types.md) 篇章中 [协议组合类型](../chapter3/03_Types.md#protocol-composition-type-h) 章节的讨论,现在协议组合类型支持进行父类约束了。
|
||||
* 更新 [拓展声明](../chapter3/06_Declarations.md#extension-declaration) 中有关协议扩展的讨论,现在它们不支持 `final` 特性了。
|
||||
* 在 [断言和前置条件](../chapter2/01_TheBasics.md#assertions-and-preconditions) 章节中新增了部分前置条件和致命错误的内容。
|
||||
|
||||
### 2017-03-27
|
||||
|
||||
* 更新至 Swift 3.1。
|
||||
* 增加[范型 Where 子句扩展](../chapter2/22_Generics.md#extensions-with-a-generic-where-clause),其中包含需要的扩展信息。
|
||||
* 增加了一个区间迭代的例子到[For-In 循环](../chapter2/05_Control_Flow.md#for-in-loops)。
|
||||
* 增加一个可失败数值转换的例子[到可失败构造器](../chapter2/14_Initialization.md#failable-initializers)章节。
|
||||
* 增加关于使用 Swift 语言版本的 `available` 特性内容到[声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes)章节。
|
||||
* 更新了[函数类型](../chapter3/03_Types.md#function_type)章节中的描述,注意在写函数类型时不允许使用参数标签。
|
||||
* 更新了[条件编译块](../chapter3/05_Statements.md#Conditional-Compilation-Block)章节中的 Swift 语言版本号的描述,现在可以使用可选的补丁版本号。
|
||||
* 更新了[函数类型](../chapter3/03_Types.md#function_type)>章节的描述,现在 Swift 区分了采用多参数的函数和采用元组类型的单个参数的函数。
|
||||
* 从[表达式](../chapter3/04_Expressions.md)章节中删除了动态表达式的部分,现在 `type(of:)` 是 Swift 标准库函数。
|
||||
* 新增 [范型 Where 子句扩展](../chapter2/22_Generics.md#extensions-with-a-generic-where-clause) 章节,包含需要的扩展内容。
|
||||
* 在 [For-In 循环](../chapter2/05_Control_Flow.md#for-in-loops) 章节中新增了区间迭代的例子。
|
||||
* 在 [到可失败构造器](http://typora-app/chapter2/14_Initialization.md#failable-initializers) 章节中新增了可失败数值转换的例子。
|
||||
* 在 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关使用 Swift 语言版本的 `available` 特性的内容 。
|
||||
* 更新 [函数类型](../chapter3/03_Types.md#function-type-h) 章节中的讨论,注意在写函数类型时不允许使用参数标签。
|
||||
* 更新 [条件编译块](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节中的 Swift 语言版本号的讨论,现在可以使用可选的补丁版本号。
|
||||
* 更新 [函数类型](../chapter3/03_Types.md#function-type-h) 章节的讨论,现在 Swift 区分了采用多参数的函数和采用元组类型的单个参数的函数。
|
||||
* 在 [表达式](../chapter3/04_Expressions.md) 篇章中删除了动态表达式的章节,现在 `type(of:)` 是 Swift 标准库函数。
|
||||
|
||||
### 2016-10-27
|
||||
|
||||
* 更新至 Swift 3.0.1。
|
||||
* 更新[自动引用计数](../chapter2/23_Automatic_Reference_Counting.md)章节中关于 weak 和 unowned 引用的讨论。
|
||||
* 增加[声明标识符](../chapter3/06_Declarations.md#declaration-modifiers)章节中关于新的标识符 `unowned`,`unowend(safe)` 和 `unowned(unsafe)` 的描述。
|
||||
* 增加[Any 和 AnyObject 的类型转换](../chapter2/18_Type_Casting.md#type-casting-for-any-and-anyobject)一节中关于使用类型 `Any` 作为可选值的描述。
|
||||
* 更新 [自动引用计数](../chapter2/23_Automatic_Reference_Counting.md) 章节中有关 weak 和 unowned 引用的讨论。
|
||||
* 在 [声明标识符](../chapter3/06_Declarations.md#declaration-modifiers) 章节中新增了有关新的标识符 `unowned`,`unowend(safe)` 和 `unowned(unsafe)` 的内容。
|
||||
* 在 [Any 和 AnyObject 的类型转换](../chapter2/18_Type_Casting.md#type-casting-for-any-and-anyobject) 章节中新增了一处说明,有关使用类型 `Any` 作为可选值。
|
||||
* 更新 [表达式](../chapter3/04_Expressions.md) 章节,把括号表达式和元组表达式的描述分开。
|
||||
|
||||
### 2016-09-13
|
||||
|
||||
* 更新至 Swift 3.0。
|
||||
* 更新[函数](../chapter2/06_Functions.md)一章和[函数声明](../chapter3/06_Declarations.md#function-declaration)部分关于函数的讨论,在一节中,标明所有函数参数默认都有函数标签。
|
||||
* 更新[高级操作符](../chapter2/26_Advanced_Operators.md)章节中关于操作符的讨论,现在你可以作为类型函数来实现,替代之前的全局函数实现方式。
|
||||
* 增加[访问控制](../chapter2/25_Access_Control.md)章节中关于对新的访问级别描述符 `open` 和 `fileprivate` 的信息。
|
||||
* 更新[函数声明](../chapter3/06_Declarations.md#function-declaration)中关于 `inout` 的讨论,注意它现在出现在参数类型的前面,而不是在参数名称的前面。
|
||||
* 更新[逃逸闭包](../chapter2/07_Closures.md#escaping-closures)和[自动闭包](../chapter2/07_Closures.md#autoclosures)还有[属性](../chapter3/07_Attributes.md)章节中关于 `@noescape` 和 `@autoclosure` 的讨论,现在他们是类型属性,而不是定义属性。
|
||||
* 增加[高级操作符](../chapter2/26_Advanced_Operators.md)一章中[自定义中缀操作符的优先级](./chapter2/26_Advanced_Operators.md#precedence-and-associativity-for-custom-infix-operators)部分和[定义](../chapter3/06_Declarations.md)一章中[优先级组声明](../chapter3/06_Declarations.md#precedence-group-declaration-modifiers)部分中关于操作符优先级组的信息。
|
||||
* 更新一些讨论:使用 macOS 替换掉 OS X, Error 替换掉 ErrorProtocol,和更新一些协议名称,比如使用 ExpressibleByStringLiteral 替换掉 StringLiteralConvertible。
|
||||
* 更新[泛型](../chapter2/22_Generics.md)和[泛型形参和实参](../chapter3/09_Generic_Parameters_And_Arguments.md)章节中[泛型 Where 语句](../chapter2/22_Generics.md#extensions-with-a-generic-where-clause)部分,现在泛型的 where 语句写在一个声明的最后。
|
||||
* 更新[逃逸闭包](../chapter2/07_Closures.md#escaping-closures)一节,现在闭包默认为非逃逸的(noescaping)。
|
||||
* 更新[基础部分](../chapter2/01_TheBasics.md)一章中[可选绑定](../chapter2/01_TheBasics.md#optional-binding)部分和[语句](../chapter3/05_Statements.md)一章中[While 语句](../chapter3/05_Statements.md#while-statement)部分,现在 if,`while` 和 `guard` 语句使用逗号分隔条件列表,不需要使用 `where` 语句。
|
||||
* 在[控制流](../chapter2/05_Control_Flow.md)一章的[Switch](../chapter2/05_Control_Flow.md#switch)和[语句](../chapter3/05_Statements.md)一章的[Switch 语句](../chapter3/05_Statements.md#switch-statement)部分中增加关于 switch cases 可以使用多模式的信息。
|
||||
* 更新[函数类型](../chapter3/03_Types.md#function_type)一节,现在函数参数标签不包含在函数类型中。
|
||||
* 更新[协议](../chapter2/21_Protocols.md)一章[协议组合](../chapter2/21_Protocols.md#protocol-composition)部分和[类型](../chapter3/03_Types.md)一章[协议组合类型](../chapter3/03_Types.md#protocol-composition)部分关于使用新的 Protocol1 & Protocol2 语法的信息。
|
||||
* 更新动态类型表达式一节使用新的 `type(of:)` 表达式的信息。
|
||||
* 更新[行控制表达式](../chapter3/05_Statements.md#line-control-statement)一节使用 `#sourceLocation(file:line:)` 表达式的信息。
|
||||
* 更新[永不返回函数](../chapter3/06_Declarations.md#functions-that-never-return)一节使用 新的 `Never` 类型的信息。
|
||||
* 增加[字面量表达式](../chapter3/04_Expressions.md#literal-expression)一节关于 `playground` 字面量的信息。
|
||||
* 更新[In-Out 参数](../chapter3/06_Declarations.md#in-out_parameters)一节,标明只有非逃逸闭包能捕获 `in-out` 参数。
|
||||
* 更新[默认参数值](../chapter2/06_Functions.md#default-parameter-values)一节,现在默认参数不能在调用时候重新排序。
|
||||
* 更新[属性](../chapter3/07_Attributes.md)章节中关于属性参数使用分号的说明。
|
||||
* 增加[重新抛出函数和方法](../chapter3/06_Declarations.md#rethrowing-functions-and-methods)一节中关于在 catch 代码块中抛出错误的重新抛出函数的信息。
|
||||
* 增加[Selector 表达式](../chapter3/04_Expressions.md#selector-expression7)一节中关于访问 Objective-C 中 Selector 的 getter 和 setter 的信息。
|
||||
* 增加[类型别名声明](../chapter3/06_Declarations.md#type-alias-declaration)一节,标明函数类型作为参数类型必须使用括号包裹。
|
||||
* 增加[函数类型](../chapter3/03_Types.md#function_type)一节中关于泛型类型别名和在协议内使用类型别名的信息。
|
||||
* 更新[属性](../chapter3/07_Attributes.md)章节,标明 `@IBAction`,`@IBOutlet` 和 `@NSManaged` 隐式含有 `@objc` 属性。
|
||||
* 增加[声明属性](../chapter3/07_Attributes.md#Ideclaration-attributes)一节中关于 `@GKInspectable` 的信息。
|
||||
* 更新[可选协议要求](../chapter2/21_Protocols.md#optional-protocol-requirements)一节中关于只能在与 `Objective-C` 交互的代码中才能使用可选协议要求的信息。
|
||||
* 删除[函数声明](../chapter3/06_Declarations.md#function-declaration)一节中关于显式使用 `let` 关键字作为函数参数的信息。
|
||||
* 删除[语句](../chapter3/05_Statements.md)一节中关于 `Boolean` 协议的信息, 现在这个协议已经被 Swift 标准库删除。
|
||||
* 更正[声明属性](../chapter3/07_Attributes.md#Ideclaration-attributes)一节中关于 `@NSApplicationMain` 协议的信息。
|
||||
* 更新 [函数](../chapter2/06_Functions.md) 篇章和 [函数声明](../chapter3/06_Declarations.md#function-declaration) 章节中有关函数的讨论,所有函数参数默认都有函数标签。
|
||||
* 更新 [高级操作符](../chapter2/26_Advanced_Operators.md) 篇章中有关操作符的讨论,现在你可以作为类型函数来实现,替代之前的全局函数实现方式。
|
||||
* 在 [访问控制](../chapter2/25_Access_Control.md) 章节中新增有关对新的访问级别描述符 `open` 和 `fileprivate` 的内容。
|
||||
* 更新 [函数声明](../chapter3/06_Declarations.md#function-declaration) 章节中有关 `inout` 的讨论,注意它现在出现在参数类型的前面,而不是在参数名称的前面。
|
||||
* 更新 [逃逸闭包](../chapter2/07_Closures.md#escaping-closures) 和 [自动闭包](../chapter2/07_Closures.md#autoclosures) 章节还有 [属性](../chapter3/07_Attributes.md) 篇章中有关 `@noescape` 和 `@autoclosure` 的讨论,现在他们是类型属性,而不是定义属性。
|
||||
* 在 [高级操作符](../chapter2/26_Advanced_Operators.md) 篇章中 [自定义中缀操作符的优先级](./chapter2/26_Advanced_Operators.md#precedence-and-associativity-for-custom-infix-operators) 章节和 [定义](../chapter3/06_Declarations.md) 篇章中 [优先级组声明](../chapter3/06_Declarations.md#precedence-group-declaration-modifiers) 章节中新增了有关操作符优先级组的内容。
|
||||
* 更新一些讨论,使用 macOS 替换掉 OS X, Error 替换掉 ErrorProtocol。更新一些协议名称,比如使用 ExpressibleByStringLiteral 替换掉 StringLiteralConvertible。
|
||||
* 更新 [泛型](../chapter2/22_Generics.md) 篇章中 [泛型 Where 语句](../chapter2/22_Generics.md#extensions-with-a-generic-where-clause) 章节和 [泛型形参和实参](../chapter3/09_Generic_Parameters_And_Arguments.md) 篇章的讨论,现在泛型的 where 语句写在一个声明的最后。
|
||||
* 更新 [逃逸闭包](../chapter2/07_Closures.md#escaping-closures) 章节中的讨论,现在闭包默认为非逃逸的。
|
||||
* 更新 [基础部分](../chapter2/01_TheBasics.md) 篇章中 [可选绑定](../chapter2/01_TheBasics.md#optional-binding) 章节和 [语句](../chapter3/05_Statements.md) 篇章中 [While 语句](../chapter3/05_Statements.md#while-statement) 章节中的讨论,现在 if,`while` 和 `guard` 语句使用逗号分隔条件列表,不需要使用 `where` 语句。
|
||||
* 在 [控制流](../chapter2/05_Control_Flow.md) 篇章中 [Switch](../chapter2/05_Control_Flow.md#switch) 章节和 [语句](../chapter3/05_Statements.md) 篇章中 [Switch 语句](../chapter3/05_Statements.md#switch-statement) 章节中新增了 switch cases 可以使用多模式的内容。
|
||||
* 更新 [函数类型](../chapter3/03_Types.md#function-type-h) 章节有关现在函数参数标签不包含在函数类型中的讨论。
|
||||
* 更新 [协议](../chapter2/21_Protocols.md) 篇章中 [协议组合](../chapter2/21_Protocols.md#protocol-composition) 章节和 [类型](../chapter3/03_Types.md) 篇章中 [协议组合类型](../chapter3/03_Types.md#protocol-composition-type-h) 章节中有关使用新的 Protocol1 & Protocol2 语法的内容。
|
||||
* 更新动态类型表达式章节中使用新的 `type(of:)` 表达式的讨论。
|
||||
* 更新 [行控制表达式](../chapter3/05_Statements.md#line-control-statement) 章节中使用 `#sourceLocation(file:line:)` 表达式的讨论。
|
||||
* 更新 [永不返回函数](../chapter3/06_Declarations.md#functions-that-never-return) 章节中使用 新的 `Never` 类型的讨论。
|
||||
* 在 [字面量表达式](../chapter3/04_Expressions.md#literal-expression) 章节中新增了有关 `playground` 字面量的内容。
|
||||
* 更新 [In-Out 参数](../chapter3/06_Declarations.md#in-out_parameters) 章节,标明只有非逃逸闭包能捕获 `in-out` 参数。
|
||||
* 更新 [默认参数值](../chapter2/06_Functions.md#default-parameter-values) 章节,现在默认参数不能在调用时候重新排序。
|
||||
* 更新 [属性](../chapter3/07_Attributes.md) 篇章中有关属性参数使用分号的说明。
|
||||
* 在 [重新抛出函数和方法](../chapter3/06_Declarations.md#rethrowing-functions-and-methods) 章节中新增了有关在 catch 代码块中抛出错误的重新抛出函数的内容。
|
||||
* 在 [Selector 表达式](../chapter3/04_Expressions.md#selector-expression7) 章节中新增了中有关访问 Objective-C 中 Selector 的 getter 和 setter 的内容。
|
||||
* 在 [类型别名声明](../chapter3/06_Declarations.md#type-alias-declaration) 章节中中新增了有关泛型类型别名和在协议内使用类型别名的内容。
|
||||
* 更新 [函数类型](../chapter3/03_Types.md#function-type-h) 章节中有关函数类型的讨论,标明函数类型作为参数类型必须使用括号包裹。
|
||||
* 更新 [属性](../chapter3/07_Attributes.md) 篇章,标明 `@IBAction`,`@IBOutlet` 和 `@NSManaged` 隐式含有 `@objc` 属性。
|
||||
* 在 [声明属性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中新增了有关 `@GKInspectable` 的内容。
|
||||
* 更新 [可选协议要求](../chapter2/21_Protocols.md#optional-protocol-requirements) 章节中有关只能在与 `Objective-C` 交互的代码中才能使用可选协议要求的内容。
|
||||
* 删除 [函数声明](../chapter3/06_Declarations.md#function-declaration) 章节中有关显式使用 `let` 关键字作为函数参数的内容。
|
||||
* 删除 [语句](../chapter3/05_Statements.md) 章节中有关 `Boolean` 协议的内容, 现在这个协议已经被 Swift 标准库删除。
|
||||
* 更正 [声明属性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@NSApplicationMain` 协议的内容。
|
||||
|
||||
### 2016-03-21
|
||||
|
||||
* 更新至 Swift 2.2。
|
||||
* 增加了[编译配置语句](../chapter3/05_Statements.md#Conditional-Compilation-Block)一节中关于如何根据 Swift 版本进行条件编译。
|
||||
* 增加了[显示成员表达式](../chapter3/04_Expressions.md#explicit-member-expression)一节中关于如何区分只有参数名不同的方法和构造器的信息。
|
||||
* 增加了[选择器表达式](../chapter3/04_Expressions.md#selector-expression7)一节中针对 Objective-C 选择器的 `#selector` 语法。
|
||||
* 更新了[关联类型](../chapter2/22_Generics.md#associated-types)和[协议关联类型声明](../chapter3/06_Declarations.md#protocol_associated_type_declaration)中的关于使用 `associatedtype` 关键词修饰关联类型的讨论。
|
||||
* 更新了[可失败构造器](../chapter2/14_Initialization.md#failable-initializers)一节中关于当构造器在实例完全初始化之前返回 `nil` 的相关信息。
|
||||
* 增加了[比较运算符](../chapter2/BasicOperators.md#comparison-operators)一节中关于比较元组的信息。
|
||||
* 增加了[关键字和标点符号](../chapter3/02_Lexical_Structure.md#keywords-and-punctuation)一节中关于使用关键字作为外部参数名的信息。
|
||||
* 增加了[声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes)一节中关于 `@objc` 特性的讨论,并指出枚举和枚举用例。
|
||||
* 增加了[操作符](../chapter3/02_Lexical_Structure.md#operator)一节中对于自定义运算符的讨论包含了 `.`。
|
||||
* 增加了[重新抛出错误的函数和方法](../chapter3/06_Declarations.md#rethrowing-functions-and-methods)一节中关于重新抛出错误函数不能直接抛出错误的笔记。
|
||||
* 增加了[属性观察器](../chapter2/10_Properties.md#property-observers)一节中关于当作为 in-out 参数传递属性时,属性观察器的调用行为。
|
||||
* 增加了[Swift 初见](./03_a_swift_tour.md)一节中关于错误处理的内容。
|
||||
* 更新了[弱引用](../chapter2/23_Automatic_Reference_Counting.md#weak-references)一节中的图片用以更清楚的展示重新分配过程。
|
||||
* 删除了 C 语言风格的 `for` 循环,`++` 前缀和后缀运算符,以及 `--` 前缀和后缀运算符。
|
||||
* 删除了对变量函数参数和柯里化函数的特殊语法的讨论。
|
||||
* 在 [编译配置语句](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节新增了中有关如何根据 Swift 版本进行条件编译。
|
||||
* 在 [显示成员表达式](../chapter3/04_Expressions.md#explicit-member-expression) 章节中新增了有关如何区分只有参数名不同的方法和构造器的内容。
|
||||
* 在 [选择器表达式](../chapter3/04_Expressions.md#selector-expression7) 章节中新增了了针对 Objective-C 选择器的 `#selector` 语法。
|
||||
* 更新 [关联类型](../chapter2/22_Generics.md#associated-types) 和 [协议关联类型声明](../chapter3/06_Declarations.md#protocol_associated_type_declaration) 章节中有关使用 `associatedtype` 关键词修饰关联类型的讨论。
|
||||
* 更新 [可失败构造器](../chapter2/14_Initialization.md#failable-initializers) 章节中有关当构造器在实例完全初始化之前返回 `nil` 的相关内容。
|
||||
* 在 [比较运算符](../chapter2/BasicOperators.md#comparison-operators) 章节中新增了比较元组的内容。
|
||||
* 在 [关键字和标点符号](../chapter3/02_Lexical_Structure.md#keywords-and-punctuation) 章节中新增了使用关键字作为外部参数名的内容。
|
||||
* 更新 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@objc` 特性的讨论,并指出枚举和枚举用例。
|
||||
* 更新 [操作符](../chapter3/02_Lexical_Structure.md#operator) 章节中对于自定义运算符的包含了 `.` 的讨论。
|
||||
* 在 [重新抛出错误的函数和方法](../chapter3/06_Declarations.md#rethrowing-functions-and-methods) 章节中新增了一处说明,重新抛出错误函数不能直接抛出错误。
|
||||
* 在 [属性观察器](../chapter2/10_Properties.md#property-observers) 章节中新增了一处说明,当作为 in-out 参数传递属性时,属性观察器的调用行为。
|
||||
* 在 [Swift 初见](./03_a_swift_tour.md) 篇章中新增了错误处理的章节。
|
||||
* 更新 [弱引用](../chapter2/23_Automatic_Reference_Counting.md#weak-references) 章节中的图片用以更清楚的展示重新分配过程。
|
||||
* 删除 C 语言风格的 `for` 循环,`++` 前缀和后缀运算符,以及 `--` 前缀和后缀运算符。
|
||||
* 删除对变量函数参数和柯里化函数的特殊语法的讨论。
|
||||
|
||||
### 2015-10-20
|
||||
|
||||
* 更新至 Swift 2.1。
|
||||
* 更新了[字符串插值](../chapter2/03_Strings_And_Characters.md#string-interpolation)和[字符串字面量](../chapter3/02_Lexical_Structure.md#string-literal)小节,现在字符串插值可包含字符串字面量。
|
||||
* 增加了在[逃逸闭包](../chapter2/07_Closures.md#escaping-closures)一节中关于 `@noescape` 属性的相关内容。
|
||||
* 更新了[声明特性]((../chapter3/07_Attributes.md#Ideclaration-attributes)和[编译配置语句](../chapter3/05_Statements.md#Conditional-Compilation-Block)小节中与 tvOS 相关的信息。
|
||||
* 增加了[In-Out 参数](../chapter3/06_Declarations.md#in-out_parameters)小节中与 in-out 参数行为相关的信息。
|
||||
* 增加了在[捕获列表](../chapter3/04_Expressions.md#capture-lists)一节中关于指定闭包捕获列表被捕获时捕获值的相关内容。
|
||||
* 更新了使用[可选链式调用访问属性](../chapter2/16_Optional_Chaining.md#accessing-properties-through-optional-chaining)一节,阐明了如何通过可选链式调用进行赋值。
|
||||
* 改进了[自动闭包](../chapter2/07_Closures.md#autoclosures)一节中对自闭包的讨论。
|
||||
* 在[Swift 初见](./03_a_swift_tour.md)一节中更新了一个使用 `??` 操作符的例子。
|
||||
* 更新 [字符串插值](../chapter2/03_Strings_And_Characters.md#string-interpolation) 和 [字符串字面量](../chapter3/02_Lexical_Structure.md#string-literal) 章节,现在字符串插值可包含字符串字面量。
|
||||
* 在 [逃逸闭包](../chapter2/07_Closures.md#escaping-closures) 章节中新增了有关 `@noescape` 属性的相关内容。
|
||||
* 更新 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 和 [编译配置语句](../chapter3/05_Statements.md#Conditional-Compilation-Block) 章节中与 tvOS 相关的内容。
|
||||
* 在 [In-Out 参数](../chapter3/06_Declarations.md#in-out_parameters) 章节中新增了与 in-out 参数行为相关的内容。
|
||||
* 在 [捕获列表](../chapter3/04_Expressions.md#capture-lists) 章节新增了有关指定闭包捕获列表被捕获时捕获值的相关内容。
|
||||
* 更新 [可选链式调用访问属性](../chapter2/16_Optional_Chaining.md#accessing-properties-through-optional-chaining) 章节,阐明了如何通过可选链式调用进行赋值。
|
||||
* 改进 [自动闭包](../chapter2/07_Closures.md#autoclosures) 章节中对自闭包的讨论。
|
||||
* 在 [Swift 初见](./03_a_swift_tour.md) 篇章中新增了一个使用 `??` 操作符的例子。
|
||||
|
||||
### 2015-09-16
|
||||
|
||||
* 更新至 Swift 2.0。
|
||||
* 在[错误处理](../chapter2/17_Error_Handling.md)一章中增加了关于错误处理的相关内容,包括[Do 语句](../chapter3/05_Statements.md#do-statement)、[Throw 语句](../chapter3/05_Statements.md#throw-statement)、[Defer 语句](../chapter3/05_Statements.md##defer-statements)以及[try 运算符](../chapter3/04_Expressions.md#try-operator)。
|
||||
* 更新了[错误表示和抛出](../chapter2/17_Error_Handling.md#representing-and-throwing-errors)一节,现在所有类型都可以遵循 `ErrorType` 协议了。
|
||||
* 在[将错误装换成可选值](../chapter2/17_Error_Handling.md#converting_errors_to_optional_values)一节增加了 `try` 关键字相关信息。
|
||||
* 在[枚举](../chapter2/08_Enumerations.md)一章的[递归枚举](../chapter2/08_Enumerations.md#recursive-enumerations)部分以及以及[声明](../chapter3/06_Declarations.md)一章的[任意类型用例的枚举](../chapter3/06_Declarations.md#enumerations-with-cases-of-any-type)一节中新增了递归枚举相关信息。
|
||||
* 在[控制流](../chapter2/05_Control_Flow.md)一章的[API 可用性检查](../chapter2/05_Control_Flow.md#checking-api-availability)一节和[语句](../chapter3/05_Statements.md)一章的[可用性条件一节](../chapter3/05_Statements.md#availability-condition)中增加了关于 API 可用性检查相关的内容。
|
||||
* 在[控制流](../chapter2/05_Control_Flow.md)一章的[尽早退出](../chapter2/05_Control_Flow.md#early-exit)一节和[语句](../chapter3/05_Statements.md)一章的[Guard 语句](../chapter3/05_Statements.md#guard-statement)部分新增了与 `guard` 语句相关的内容。
|
||||
* 在[协议](../chapter2/21_Protocols.md)一章中[协议扩展](../chapter2/21_Protocols.md#protocol-extensions)一节中新增了关于协议扩展的内容。
|
||||
* 在[访问控制](../chapter2/25_Access_Control.md)一章的[单元测试 target 的访问级别](../chapter2/25_Access_Control.md#access-levels-for-unit-test-targets)一节中新增了关于单元测试访问控制相关的内容。
|
||||
* 在[模式](../chapter3/08_Patterns.md)一章的[可选模式](../chapter3/08_Patterns.md#optional-pattern)一节中增加了可选模式相关内容。
|
||||
* 更新了[Repeat-While](../chapter2/05_Control_Flow.md#repeat-while)一节中关于 `repeat-while` 循环相关的内容。
|
||||
* 更新了[字符串和字符](../chapter2/03_Strings_And_Characters.md)一章,现在 `String` 类型在 Swift 标准库中不再遵循 `CollectionType` 协议。
|
||||
* 在[常量与变量打印](../chapter2/01_TheBasics.md#printing)一节中增加了新 Swift 标准库中关于 `print(_:separator:terminator)` 相关内容。
|
||||
* 在[枚举](../chapter2/08_Enumerations.md)一章中的[原始值的隐式赋值](../chapter2/08_Enumerations.md#implicitly-assigned-raw-values)一节和[声明](../chapter3/06_Declarations.md)一章的[包含原始值类型的枚举](../chapter3/06_Declarations.md#enumerations-with-cases-of-a-raw-value-type)一节中增加了关于包含 `String` 原始值的枚举用例的行为相关内容。
|
||||
* 在[自动闭包](../chapter2/07_Closures.md#autoclosures)一节中增加了关于 `@autoclosure` 特性的相关信息,包括它的 `@autoclosure(escaping)` 形式。
|
||||
* 更新了[声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes)一节中关于 `@avaliable` 和 `warn_unused_result` 特性的相关内容。
|
||||
* 更新了[类型特性](../chapter3/07_Attributes.md#type-attributes)一节中关于 `@convention` 特性的相关信息。
|
||||
* 在[可选绑定](../chapter2/01_TheBasics.md#optional-binding)一节中增加了关于使用 `where` 子句进行多可选绑定的相关内容。
|
||||
* 在[字符串字面量](../chapter3/02_Lexical_Structure.md#string-literal)一节中新增了关于在编译时使用 `+` 运算符拼接字符串字面量的相关信息。
|
||||
* 在[元类型](../chapter3/03_Types.md#metatype-type)一节中新增了关于元类型值的比较和使用它们通过构造器表达式构造实例相关内容。
|
||||
* 在[断言调试](../chapter2/01_TheBasics.md#debugging-with-assertions)一节中新增了关于用户定义断言何时会失效的注释内容。
|
||||
* 更新了[声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes)一节中对 `@NSManaged` 特性的讨论,现在这个特性可以被应用到一个确定实例方法。
|
||||
* 更新了[可变参数](../chapter2/06_Functions.md#variadic-parameters)一节,现在可变参数可以声明在函数参数列表的任意位置中。
|
||||
* 在[重写可失败构造器](../chapter2/14_Initialization.md#overriding-a-failable-initializer)一节中新增了关于非可失败构造器相当于一个可失败构造器通过父类构造器的结果进行强制拆包的相关内容。
|
||||
* 在[任意类型用例的枚举](../chapter3/06_Declarations.md#enumerations-with-cases-of-any-type)一节中增加了关于枚举用例作为函数的内容。
|
||||
* 在[构造器表达式](../chapter3/04_Expressions.md#initializer-expression)一节中新增关于显式引用一个构造器相关内容。
|
||||
* 在[编译控制语句](../chapter3/05_Statements.md#compiler-control-statements)一节中新增了关于编译信息以及行控制语句相关信息。
|
||||
* 在[元类型](../chapter3/03_Types.md#metatype-type)一节中新增了关于如何从元类型值中构造类实例相关内容。
|
||||
* 在[弱引用](../chapter2/23_Automatic_Reference_Counting.md#weak-references)一节中关于弱引用作为缓存所存在的不足的注释说明。
|
||||
* 更新了[类型特性](../chapter2/10_Properties.md#type-properties)一节,提到了存储型特性其实是懒加载。
|
||||
* 更新了[捕获类型](../chapter2/07_Closures.md#capturing_values)一节,阐明了变量和常量在闭包中如何被捕获。
|
||||
* 更新了[声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes)一节,用以描述何时在类中使用 `@objc` 关键字。
|
||||
* 在[错误处理](../chapter2/17_Error_Handling.md#handling-errors)一节中增加了关于执行 `throw` 语句的性能的讨论。在[Do 语句](../chapter3/05_Statements.md#do-statement)一节的 do 语句部分也增加了类似内容。
|
||||
* 更新了[类型特性](../chapter2/10_Properties.md#type-properties)一节中关于类、结构体和枚举的存储型和计算型特性相关的内容。
|
||||
* 更新了[Break 语句](../chapter3/05_Statements.md#break_statement)一节中关于带标签的 break 语句相关内容。
|
||||
* 在[属性观察器](../chapter2/10_Properties.md#property-observers)一节中更新了一处注释,用来明确 `willSet` 和 `didSet` 观察器的行为。
|
||||
* 在[访问级别](../chapter2/25_Access_Control.md#access-levels)一节中新增了关于 `private` 作用域的相关信息说明。
|
||||
* 在[弱引用](../chapter2/23_Automatic_Reference_Counting.md#weak-references)一节中增加了关于弱应用在垃圾回收系统和 ARC 之间的区别的说明。
|
||||
* 更新了[字符串字面量中特殊字符](../chapter2/03_Strings_And_Characters.md#special-characters-in-string-literals)一节中对 Unicode 标量更精确的定义。
|
||||
* 在 [错误处理](../chapter2/17_Error_Handling.md) 篇章中新增了有关错误处理的相关内容,包括 [Do 语句](../chapter3/05_Statements.md#do-statement)、 [Throw 语句](../chapter3/05_Statements.md#throw-statement)、 [Defer 语句](../chapter3/05_Statements.md##defer-statements) 以及 [try 运算符](../chapter3/04_Expressions.md#try-operator)。
|
||||
* 更新 [错误表示和抛出](../chapter2/17_Error_Handling.md#representing-and-throwing-errors) 章节,现在所有类型都可以遵循 `ErrorType` 协议了。
|
||||
* 在 [将错误装换成可选值](../chapter2/17_Error_Handling.md#converting_errors_to_optional_values) 篇章增加了 `try?` 关键字相关内容。
|
||||
* 在 [枚举](../chapter2/08_Enumerations.md) 篇章的 [递归枚举](../chapter2/08_Enumerations.md#recursive-enumerations) 章节以及以及 [声明](../chapter3/06_Declarations.md) 篇章的 [任意类型用例的枚举](../chapter3/06_Declarations.md#enumerations-with-cases-of-any-type) 章节中新增了递归枚举相关内容。
|
||||
* 在 [控制流](../chapter2/05_Control_Flow.md) 篇章的 [API 可用性检查](../chapter2/05_Control_Flow.md#checking-api-availability) 章节和 [语句](../chapter3/05_Statements.md) 篇章的 [可用性条件](../chapter3/05_Statements.md#availability-condition) 章节中新增了有关 API 可用性检查相关的内容。
|
||||
* 在 [控制流](../chapter2/05_Control_Flow.md) 篇章的 [尽早退出](../chapter2/05_Control_Flow.md#early-exit) 章节和 [语句](../chapter3/05_Statements.md) 篇章的 [Guard 语句](../chapter3/05_Statements.md#guard-statement) 章节新增了与 `guard` 语句相关的内容。
|
||||
* 在 [协议](../chapter2/21_Protocols.md) 篇章中 [协议扩展](../chapter2/21_Protocols.md#protocol-extensions) 章节中新增了有关协议扩展的内容。
|
||||
* 在 [访问控制](../chapter2/25_Access_Control.md) 篇章的 [单元测试 target 的访问级别](../chapter2/25_Access_Control.md#access-levels-for-unit-test-targets) 章节中新增了有关单元测试访问控制相关的内容。
|
||||
* 在 [模式](../chapter3/08_Patterns.md) 篇章的 [可选模式](../chapter3/08_Patterns.md#optional-pattern) 章节中新增了可选模式相关内容。
|
||||
* 更新 [Repeat-While](../chapter2/05_Control_Flow.md#repeat-while) 章节中有关 `repeat-while` 循环相关的内容。
|
||||
* 更新 [字符串和字符](../chapter2/03_Strings_And_Characters.md) 章节,现在 `String` 类型在 Swift 标准库中不再遵循 `CollectionType` 协议。
|
||||
* 在 [常量与变量打印](../chapter2/01_TheBasics.md#printing) 章节中新增了新 Swift 标准库中有关 `print(_:separator:terminator) ` 相关内容。
|
||||
* 在 [枚举](../chapter2/08_Enumerations.md) 篇章的 [原始值的隐式赋值](../chapter2/08_Enumerations.md#implicitly-assigned-raw-values) 章节和 [声明](../chapter3/06_Declarations.md) 篇章的 [包含原始值类型的枚举](../chapter3/06_Declarations.md#enumerations-with-cases-of-a-raw-value-type) 章节中新增了有关包含 `String` 原始值的枚举用例的行为相关内容。
|
||||
* 在 [自动闭包](../chapter2/07_Closures.md#autoclosures) 章节中新增了有关 `@autoclosure` 特性的相关内容,包括它的 `@autoclosure(escaping)` 形式。
|
||||
* 更新 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中有关 `@avaliable` 和 `warn_unused_result` 特性的相关内容。
|
||||
* 更新 [类型特性](../chapter3/07_Attributes.md#type-attributes) 章节中有关 `@convention` 特性的相关内容。
|
||||
* 在 [可选绑定](../chapter2/01_TheBasics.md#optional-binding) 章节中新增了有关使用 `where` 子句进行多可选绑定的相关内容。
|
||||
* 在 [字符串字面量](../chapter3/02_Lexical_Structure.md#string-literal) 章节中新增了有关在编译时使用 `+` 运算符拼接字符串字面量的相关内容。
|
||||
* 在 [元类型](../chapter3/03_Types.md#metatype-type-h) 章节中新增了有关元类型值的比较和使用它们通过构造器表达式构造实例相关内容。
|
||||
* 在 [断言调试](../chapter2/01_TheBasics.md#debugging-with-assertions) 章节中新增了一处说明,有关用户定义断言何时会失效。
|
||||
* 更新 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节中对 `@NSManaged` 特性的讨论,现在这个特性可以被应用到一个确定实例方法。
|
||||
* 更新 [可变参数](../chapter2/06_Functions.md#variadic-parameters) 章节,现在可变参数可以声明在函数参数列表的任意位置中。
|
||||
* 在 [重写可失败构造器](../chapter2/14_Initialization.md#overriding-a-failable-initializer) 章节中新增了有关非可失败构造器相当于一个可失败构造器通过父类构造器的结果进行强制拆包的相关内容。
|
||||
* 在 [任意类型用例的枚举](../chapter3/06_Declarations.md#enumerations-with-cases-of-any-type) 章节中新增了有关枚举用例作为函数的内容。
|
||||
* 在 [构造器表达式](../chapter3/04_Expressions.md#initializer-expression) 章节中新增了有关显式引用一个构造器相关内容。
|
||||
* 在 [编译控制语句](../chapter3/05_Statements.md#compiler-control-statements) 章节中新增了有关编译内容以及行控制语句相关内容。
|
||||
* 在 [元类型](../chapter3/03_Types.md#metatype-type-h) 章节新增了一处说明,有关如何从元类型值中构造类实例相关内容。
|
||||
* 在 [弱引用](../chapter2/23_Automatic_Reference_Counting.md#weak-references) 章节新增了一处说明,有关弱引用作为缓存所存在的不足。
|
||||
* 更新 [类型特性](../chapter2/10_Properties.md#type-properties) 章节,提到了存储型特性其实是懒加载。
|
||||
* 更新 [捕获类型](../chapter2/07_Closures.md#capturing_values) 章节,阐明了变量和常量在闭包中如何被捕获。
|
||||
* 更新 [声明特性](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节,用以描述何时在类中使用 `@objc` 关键字。
|
||||
* 在 [错误处理](../chapter2/17_Error_Handling.md#handling-errors) 章节中新增了一处说明,有关执行 `throw` 语句的性能。在 [Do 语句](../chapter3/05_Statements.md#do-statement) 章节的 do 语句部分也新增了类似内容。
|
||||
* 更新 [类型特性](../chapter2/10_Properties.md#type-properties) 章节中有关类、结构体和枚举的存储型和计算型特性相关的内容。
|
||||
* 更新 [Break 语句](../chapter3/05_Statements.md#break_statement) 章节中有关带标签的 break 语句相关内容。
|
||||
* 在 [属性观察器](../chapter2/10_Properties.md#property-observers) 章节更新了一处说明,用来明确 `willSet` 和 `didSet` 观察器的行为。
|
||||
* 在 [访问级别](../chapter2/25_Access_Control.md#access-levels) 章节新增了有关 `private` 作用域的相关内容说明。
|
||||
* 在 [弱引用](../chapter2/23_Automatic_Reference_Counting.md#weak-references) 章节新增了有关弱应用在垃圾回收系统和 ARC 之间的区别的说明。
|
||||
* 更新 [字符串字面量中特殊字符](../chapter2/03_Strings_And_Characters.md#special-characters-in-string-literals) 章节,对 Unicode 标量更精确定义。
|
||||
|
||||
|
||||
### 2015-4-8
|
||||
### 2015-04-08
|
||||
|
||||
* 更新至 Swift 1.2。
|
||||
* Swift 现在自身提供了一个 `Set` 集合类型,更多信息请看[Sets](../chapter2/CollectionTypes.md#sets)。
|
||||
* `@autoclosure` 现在是一个参数声明的属性,而不是参数类型的属性。这里还有一个新的参数声明属性 `@noescape`。更多信息,请看[属性声明](../chapter3/07_Attributes.md#Ideclaration-attributes)。
|
||||
* 对于类型属性和方法现在可以使用 `static` 关键字作为声明描述符,更多信息,请看[类型变量属性](../chapter3/06_Declarations.md#type-variable-properties)。
|
||||
* Swift 现在包含一个 `as?` 和 `as!` 的向下可失败类型转换运算符。更多信息,请看[协议遵循性检查](../chapter2/21_Protocols.md#checking-for-protocol-conformance)。
|
||||
* 增加了一个关于[字符串索引](../chapter2/03_Strings_And_Characters.md#string-indices)的新指导章节。
|
||||
* 从[溢出运算符](../chapter2/26_Advanced_Operators.md#overflow-operators)一节中移除了溢出除运算符(&/)和求余溢出运算符(&%)。
|
||||
* 更新了常量和常量属性在声明和构造时的规则,更多信息,请看[常量声明](../chapter3/06_Declarations.md#constant-declaration)。
|
||||
* 更新了字符串字面量中 Unicode 标量集的定义,请看[字符串字面量中的特殊字符](../chapter2/03_Strings_And_Characters.md#special-characters-in-string-literals)。
|
||||
* 更新了[区间运算符](../chapter2/BasicOperators.md#range-operators)章节来提示当半开区间运算符含有相同的起止索引时,其区间为空。
|
||||
* 更新了[闭包引用类型](../chapter2/07_Closures.md#closures-are-reference-types)章节来阐明对于变量的捕获规则。
|
||||
* 更新了[值溢出](../chapter2/26_Advanced_Operators.md#value-overflow)章节堆有符号整数和无符号整数的溢出行为进行了阐明。
|
||||
* 更新了[协议声明](../chapter3/06_Declarations.md#protocol-declaration)章节对协议声明时的作用域和成员等内容进行了阐明。
|
||||
* 更新了[捕获列表](../chapter2/23_Automatic_Reference_Counting.md#defining-a-capture-list)章节对于闭包捕获列表中的弱引用和无主引用的使用语法进行了阐明。
|
||||
* 更新了[运算符](../chapter3/02_Lexical_Structure.md#operator)章节,明确指明一些例子来说明自定义运算符所支持的特性,如数学运算符,各种符号,Unicode 符号块等。
|
||||
* 在函数作用域中的常量声明时可以不被初始化,它必须在第一次使用前被赋值。更多的信息,请看[常量声明](../chapter3/06_Declarations.md#constant-declaration)。
|
||||
* 在构造器中,常量属性有且仅能被赋值一次。更多信息,请看[在构造过程中给常量属性赋值](../chapter2/14_Initialization.md{#assigning-constant-properties-during-initialization)。
|
||||
* 多个可选绑定现在可以在`if`语句后面以逗号分隔的赋值列表的方式出现,更多信息,请看[可选绑定](../chapter2/01_TheBasics.md#optional-binding)。
|
||||
* Swift 现在自身提供了一个 `Set` 集合类型,更多内容,请看 [Sets](../chapter2/CollectionTypes.md#sets) 。
|
||||
* `@autoclosure` 现在是一个参数声明的属性,而不是参数类型的属性。这里还有一个新的参数声明属性 `@noescape`。更多内容,请看 [属性声明](../chapter3/07_Attributes.md#Ideclaration-attributes) 。
|
||||
* 对于类型属性和方法现在可以使用 `static` 关键字作为声明描述符,更多内容,请看 [类型变量属性](../chapter3/06_Declarations.md#type-variable-properties)。
|
||||
* Swift 现在包含一个 `as?` 和 `as!` 的向下可失败类型转换运算符。更多内容,请看 [协议遵循性检查](../chapter2/21_Protocols.md#checking-for-protocol-conformance)。
|
||||
* 新增 [字符串索引](../chapter2/03_Strings_And_Characters.md#string-indices) 的新指导章节。
|
||||
* 在 [溢出运算符](../chapter2/26_Advanced_Operators.md#overflow-operators) 一节中删除了溢出除运算符(`&/`)和求余溢出运算符(`&%`)。
|
||||
* 更新常量和常量属性在声明和构造时的规则,更多内容,请看 [常量声明](../chapter3/06_Declarations.md#constant-declaration) 。
|
||||
* 更新字符串字面量中 Unicode 标量集的定义,请看 [字符串字面量中的特殊字符](../chapter2/03_Strings_And_Characters.md#special-characters-in-string-literals) 。
|
||||
* 更新 [区间运算符](../chapter2/BasicOperators.md#range-operators) 章节,注意当半开区间运算符含有相同的起止索引时,其区间为空。
|
||||
* 更新 [闭包引用类型](../chapter2/07_Closures.md#closures-are-reference-types) 章节,对于变量的捕获规则进行了阐明。
|
||||
* 更新 [值溢出](../chapter2/26_Advanced_Operators.md#value-overflow) 章节,对有符号整数和无符号整数的溢出行为进行了阐明。
|
||||
* 更新 [协议声明](../chapter3/06_Declarations.md#protocol-declaration) 章节,对协议声明时的作用域和成员等内容进行了阐明。
|
||||
* 更新 [捕获列表](../chapter2/23_Automatic_Reference_Counting.md#defining-a-capture-list) 章节,对于闭包捕获列表中的弱引用和无主引用的使用语法进行了阐明。
|
||||
* 更新 [运算符](../chapter3/02_Lexical_Structure.md#operator) 章节,明确指明一些例子来说明自定义运算符所支持的特性,如数学运算符,各种符号,Unicode 符号块等。
|
||||
* 在函数作用域中的常量声明时可以不被初始化,它必须在第一次使用前被赋值。更多的内容,请看 [常量声明](../chapter3/06_Declarations.md#constant-declaration)。
|
||||
* 在构造器中,常量属性有且仅能被赋值一次。更多内容,请看 [在构造过程中给常量属性赋值](../chapter2/14_Initialization.md{#assigning-constant-properties-during-initialization)。
|
||||
* 多个可选绑定现在可以在`if`语句后面以逗号分隔的赋值列表的方式出现,更多内容,请看 [可选绑定](../chapter2/01_TheBasics.md#optional-binding)。
|
||||
* 一个 [可选链表达式](../chapter3/04_Expressions.md#optional-chaining-expression) 必须出现在后缀表达式中。
|
||||
* 协议类型转换不再局限于 `@obj` 修饰的协议了。
|
||||
* 在运行时可能会失败的类型转换可以使用 `as?` 和 `as!` 运算符,而确保不会失败的类型转换现在使用 `as` 运算符。更多信息,请看[类型转换运算符](../chapter3/04_Expressions.md#type-casting-operator)。
|
||||
* 在运行时可能会失败的类型转换可以使用 `as?` 和 `as!` 运算符,而确保不会失败的类型转换现在使用 `as` 运算符。更多内容,请看 [类型转换运算符](../chapter3/04_Expressions.md#type-casting-operator)。
|
||||
|
||||
### 2014-10-16
|
||||
|
||||
* 更新至 Swift 1.1。
|
||||
* 增加了关于[失败构造器](../chapter2/14_Initialization.md#failable-initializers)的完整章节。
|
||||
* 增加了协议中关于[失败构造器要求](../chapter2/21_Protocols.md#failable-initializer-requirements)的描述。
|
||||
* 常量和变量的 `Any` 类型现可以包含函数实例。更新了关于 `Any` 相关的示例来展示如何在 `switch` 语句中如何检查并转换到一个函数类型。
|
||||
* 带有原始值的枚举类型增加了一个 `rawValue` 属性替代 `toRaw()` 方法,同时使用了一个以 `rawValue` 为参数的失败构造器来替代 `fromRaw()` 方法。更多的信息,请看[原始值](../chapter2/08_Enumerations.md#raw-values)和[带原始值的枚举类型](../chapter3/06_Declarations.md#enumerations-with-cases-of-a-raw-value-type)部分。
|
||||
* 添加了一个关于 [Failable Initializer](../chapter3/06_Declarations.md#failable-initializers) 的新参考章节,它可以触发初始化失败。
|
||||
* 自定义运算符现在可以包含 `?` 字符,更新[运算符](../chapter3/02_Lexical_Structure.md#operator)章节描述了改进后的规则,并且从[自定义运算符](../chapter2/26_Advanced_Operators.md#custom-operators)章节删除了重复的运算符有效字符集合。
|
||||
* 新增 [失败构造器](../chapter2/14_Initialization.md#failable-initializers) 的完整指引。
|
||||
* 在协议中新增了 [失败构造器要求](../chapter2/21_Protocols.md#failable-initializer-requirements) 的描述。
|
||||
* 常量和变量的 `Any` 类型现可以包含函数实例。更新了有关 `Any` 相关的示例来展示如何在 `switch` 语句中如何检查并转换到一个函数类型。
|
||||
* 带有原始值的枚举类型增加了一个 `rawValue` 属性替代 `toRaw()` 方法,同时使用了一个以 `rawValue` 为参数的失败构造器来替代 `fromRaw()` 方法。更多的内容,请看 [原始值](../chapter2/08_Enumerations.md#raw-values) 和 [带原始值的枚举类型](../chapter3/06_Declarations.md#enumerations-with-cases-of-a-raw-value-type)。
|
||||
* 新增 [Failable Initializer](../chapter3/06_Declarations.md#failable-initializers) 的参考章节,它可以触发初始化失败。
|
||||
* 自定义运算符现在可以包含 `?` 字符,更新了 [运算符](../chapter3/02_Lexical_Structure.md#operator) 涉及改进后的规则的部分,并且在 [自定义运算符](../chapter2/26_Advanced_Operators.md#custom-operators) 章节中删除了重复的运算符有效字符集合。
|
||||
|
||||
### 2014-08-18
|
||||
|
||||
* 发布新的文档用以详述 Swift 1.0,苹果公司针对 iOS 和 OS X 应用的全新开发语言。
|
||||
* 在章节协议中,增加新的小节:[对构造器的规定](../chapter2/21_Protocols.md#initializer-requirements)。
|
||||
* 在章节协议中,增加新的小节:[类专属协议](../chapter2/21_Protocols.md#class-only-protocol)。
|
||||
* 描述 Swift 1.0 的新文档。Swift 是苹果公司发布的全新编程语言,用于 iOS 和 OS X 应用开发。
|
||||
* 在协议中新增了 [对构造器的规定](../chapter2/21_Protocols.md#initializer-requirements) 章节。
|
||||
* 新增 [类专属协议](../chapter2/21_Protocols.md#class-only-protocol) 章节。
|
||||
* [断言](../chapter2/01_TheBasics.md#assertions-and-preconditions) 现在可以使用字符串内插语法,并删除了文档中有冲突的注释。
|
||||
* 更新了[连接字符串和字符](../chapter2/03_Strings_And_Characters.md#concatenating-strings-and-characters)小节来说明一个事实,那就是字符串和字符不能再用 `+` 号运算符或者复合加法运算符 `+=` 相互连接,这两种运算符现在只能用于字符串之间相连。请使用 `String` 类型的 `append` 方法在一个字符串的尾部增加单个字符。
|
||||
* 在[属性申明](../chapter3/07_Attributes.md#Ideclaration-attributes)章节增加了关于 `availability` 特性的一些信息。
|
||||
* 更新 [连接字符串和字符](../chapter2/03_Strings_And_Characters.md#concatenating-strings-and-characters) 章节来说明字符串和字符不能再用 `+` 号运算符或者复合加法运算符 `+=` 相互连接,这两种运算符现在只能用于字符串之间相连。请使用 `String` 类型的 `append` 方法在一个字符串的尾部增加单个字符。
|
||||
* 在 [属性申明](../chapter3/07_Attributes.md#Ideclaration-attributes) 章节增加了有关 `availability` 特性的一些内容。
|
||||
* [可选类型](../chapter2/01_TheBasics.md#optionals) 若有值时,不再隐式的转换为 `true`,同样,若无值时,也不再隐式的转换为 `false`,这是为了避免在判别 optional `Bool` 的值时产生困惑。 替代的方案是,用`==` 或 `!=` 运算符显式地去判断 Optinal 是否是 `nil`,以确认其是否包含值。
|
||||
* Swift 新增了一个 [Nil 合并运算符](../chapter2/BasicOperators.md#nil-coalescing-operator) (`a ?? b`) , 该表达式中,如果 Optional `a` 的值存在,则取得它并返回,若 Optional `a` 为 `nil`,则返回默认值 `b`
|
||||
* 更新和扩展 [字符串的比较](../chapter2/03_Strings_And_Characters.md#comparing-strings) ,用以反映和展示'字符串和字符的比较',以及'前缀(prefix)/后缀(postfix)比较'都开始基于扩展字符集(extended grapheme clusters)规范的等价比较。
|
||||
* 现在,你可以通过下标赋值或者[可选调用链](../chapter2/16_Optional_Chaining.md)中的可变方法和操作符来给属性设值。相应地更新了有关[通过可选链接访问属性](../chapter2/16_Optional_Chaining.md#accessing-properties-through-optional-chaining)的信息,并扩展了[通过可选链接调用方法](../chapter2/16_Optional_Chaining.md#calling-methods-through-optional-chaining)时检查方法调用成功的示例,以显示如何检查属性设置是否成功。
|
||||
* 在章节可选链中,增加一个新的小节[访问可选类型的下标脚注](../chapter2/16_Optional_Chaining.md#accessing-subscripts-through-optional-chaining)。
|
||||
* 更新章节[访问和修改数组](../chapter2/CollectionTypes.md#accessing-and-modifying-a-dictionary)以标示:从该版本起,不能再通过 `+=` 运算符给一个数组添加一个新的项。对应的替代方案是,使 `append` 方法,或者通过 `+=` 运算符来添加一个只有一个项的数组。
|
||||
* 添加了一个提示:在[范围运算符](../chapter2/BasicOperators.md#range-operators)中,比如, `a..b` 和 `a..<b` ,起始值 `a` 不能大于结束值 `b`。
|
||||
* 重写了[继承](../chapter2/13_Inheritance.md)这一章:删除了本章中关于构造器重写的介绍性报道;转而将更多的注意力放到新增的部分——子类的新功能,以及如何通过重写(overrides)修改已有的功能。另外,[重写属性的 Getters 和 Setters](../chapter2/13_Inheritance.md#overriding-property-etters-and-setters)中的例子已经被替换为展示如何重写一个 `description` 属性。 (而关于如何在子类的构造器中修改继承属性的默认值的例子,已经被移到[构造过程](../chapter2/14_Initialization.md)这一章。)
|
||||
* 更新了[构造器的继承与重写](../chapter2/14_Initialization.md#initializer-inheritance-and-overriding)小节以标示: 重写一个特定的构造器必须使用 `override` 修饰符。
|
||||
* 更新[Required 构造器](../chapter2/14_Initialization.md#required-initializers)小节以标示:`required` 修饰符现在需要出现在所有子类的 required 构造器的声明中,而 required 构造器的实现,现在可以仅从父类自动继承。
|
||||
* 现在,你可以通过下标赋值或者 [可选调用链](../chapter2/16_Optional_Chaining.md) 中的可变方法和操作符来给属性设值。相应地更新了有关 [通过可选链接访问属性](../chapter2/16_Optional_Chaining.md#accessing-properties-through-optional-chaining) 的内容,并扩展了 [通过可选链接调用方法](../chapter2/16_Optional_Chaining.md#calling-methods-through-optional-chaining) 时检查方法调用成功的示例,以显示如何检查属性设置是否成功。
|
||||
* 在可选链中新增了 [访问可选类型的下标脚注](../chapter2/16_Optional_Chaining.md#accessing-subscripts-through-optional-chaining) 章节。
|
||||
* 更新 [访问和修改数组](../chapter2/CollectionTypes.md#accessing-and-modifying-a-dictionary) 章节以标示,从该版本起,不能再通过 `+=` 运算符给一个数组新增一个新的项。对应的替代方案是,使 `append` 方法,或者通过 `+=` 运算符来新增一个只有一个项的数组。
|
||||
* 新增一处说明,在 [范围运算符](../chapter2/BasicOperators.md#range-operators) 中,比如, `a..b` 和 `a..<b` ,起始值 `a` 不能大于结束值 `b`。
|
||||
* 重写 [继承](../chapter2/13_Inheritance.md) 篇章:删除了本章中有关构造器重写的介绍性报道;转而将更多的注意力放到新增的部分——子类的新功能,以及如何通过重写(overrides)修改已有的功能。另外, [重写属性的 Getters 和 Setters](../chapter2/13_Inheritance.md#overriding-property-etters-and-setters) 中的例子已经被替换为展示如何重写一个 `description` 属性。 (而有关如何在子类的构造器中修改继承属性的默认值的例子,已经被移到 [构造过程](../chapter2/14_Initialization.md) 篇章。)
|
||||
* 更新 [构造器的继承与重写](../chapter2/14_Initialization.md#initializer-inheritance-and-overriding) 章节以标示: 重写一个特定的构造器必须使用 `override` 修饰符。
|
||||
* 更新 [Required 构造器](../chapter2/14_Initialization.md#required-initializers) 章节以标示:`required` 修饰符现在需要出现在所有子类的 required 构造器的声明中,而 required 构造器的实现,现在可以仅从父类自动继承。
|
||||
* 中置(Infix)的 [运算符函数](../chapter2/26_Advanced_Operators.md#operator-functions) 不再需要 `@infix` 属性。
|
||||
* [前置和后置运算符](../chapter2/26_Advanced_Operators.md#prefix-and-postfix-operators) 的 `@prefix` 和 `@postfix` 属性,已变更为 `prefix` 和 `postfix` 声明修饰符。
|
||||
* 增加一条注解:当 Prefix 和 postfix 运算符被作用于同一个操作数时,关于[前置和后置运算符](../chapter2/26_Advanced_Operators.md#prefix-and-postfix-operators)的执行顺序。
|
||||
* 在运算符函数中,[组合赋值运算符](../chapter2/26_Advanced_Operators.md#compound-assignment-operators)不再使用 `@assignment` 属性来定义函数。
|
||||
* 在这个版本中,在定义[自定义操作符](../chapter2/26_Advanced_Operators.md#custom-operators)时,`修饰符(Modifiers)的出现顺序发生变化`。比如现在,你该编写 `prefix operator`, 而不是 `operator prefix`。
|
||||
* 在[声明修饰符](../chapter3/06_Declarations.md#declaration-modifiers)章节增加关于 `dynamic` 声明修饰符的信息。
|
||||
* 增加[字面量](../chapter3/02_Lexical_Structure.md#literal)的类型推导内容。
|
||||
* 为章节 Curried Functions 添加了更多的信息。
|
||||
* 加入新的章节[权限控制(../chapter2/25_Access_Control.md)。
|
||||
* 更新了[字符串和字符](../chapter2/03_Strings_And_Characters.md)章节用以表明,在 Swift 中,`Character` 类型现在代表的是扩展字符集(extended grapheme cluster)中的一个 Unicode,为此,新增了小节[Extended Grapheme Clusters](../chapter2/03_Strings_And_Characters.md#extended-grapheme-clusters)。同时,为小节[Unicode 标量](../chapter2/03_Strings_And_Characters.md#unicode-scalars-representation)和[字符串比较](../chapter2/03_Strings_And_Characters.md#comparing-strings)增加了更多内容。
|
||||
* 更新[字符串字面量](../chapter2/03_Strings_And_Characters.md#string-literals)章节:在一个字符串中,Unicode 标量(Unicode scalars)以 `\u{n}`的形式来表示,`n` 是一个最大可以有8位的16进制数。
|
||||
* 新增一处说明,在 Prefix 和 postfix 运算符被作用于同一个操作数时 [前置和后置运算符](../chapter2/26_Advanced_Operators.md#prefix-and-postfix-operators) 的执行顺序。
|
||||
* [组合赋值运算符](../chapter2/26_Advanced_Operators.md#compound-assignment-operators) 的运算符函数不再使用 `@assignment` 属性来定义函数。
|
||||
* 在定义 [自定义操作符](../chapter2/26_Advanced_Operators.md#custom-operators) 时,`修饰符(Modifiers)的出现顺序发生变化`。比如现在,你该编写 `prefix operator`, 而不是 `operator prefix`。
|
||||
* 在 [声明修饰符](../chapter3/06_Declarations.md#declaration-modifiers) 章节新增了有关 `dynamic` 声明修饰符的内容。
|
||||
* 新增有关 [字面量](../chapter3/02_Lexical_Structure.md#literal) 类型推导内容的内容。
|
||||
* 新增更多有关柯里化函数的内容。
|
||||
* 新增 [权限控制](../chapter2/25_Access_Control.md) 篇章。
|
||||
* 更新 [字符串和字符](../chapter2/03_Strings_And_Characters.md) 章节,在 Swift 中现在 `Character` 类型代表的是扩展字符集(extended grapheme cluster)中的一个 Unicode,为此,新增了 [Extended Grapheme Clusters](../chapter2/03_Strings_And_Characters.md#extended-grapheme-clusters) 章节。同时,[Unicode 标量](../chapter2/03_Strings_And_Characters.md#unicode-scalars-representation) 和 [字符串比较](../chapter2/03_Strings_And_Characters.md#comparing-strings) 章节新增了更多内容。
|
||||
* 更新 [字符串字面量](../chapter2/03_Strings_And_Characters.md#string-literals) 章节,在一个字符串中,Unicode 标量(Unicode scalars)以 `\u{n}`的形式来表示,`n` 是一个最大可以有8位的16进制数。
|
||||
* `NSString` `length` 属性已被映射到 Swift 的内建 `String`类型。(注意,这两属性的类型是`utf16Count`,而非 `utf16count`)。
|
||||
* Swift 的内建 `String` 类型不再拥有 `uppercaseString` 和 `lowercaseString` 属性。其对应部分在章节[字符串和字符](../chapter2/03_Strings_And_Characters.md)已经被删除,并且各种对应的代码用例也已被更新。
|
||||
* 加入新的章节[没有外部名的构造器参数](../chapter2/14_Initialization.md#initializer-parameters-without-external-names)。
|
||||
* 加入新的章节[Required 构造器](../chapter2/14_Initialization.md#required-initializers)。
|
||||
* 加入新的章节[可选元组返回类型](../chapter2/06_Functions.md#optional-tuple-return-types)。
|
||||
* 更新了[类型标注](../chapter2/01_TheBasics.md#type-annotations)章节:多个相关变量可以用"类型标注”在同一行中声明为同一类型。
|
||||
* Swift 的内建 `String` 类型不再拥有 `uppercaseString` 和 `lowercaseString` 属性。在 [字符串和字符](../chapter2/03_Strings_And_Characters.md) 章节中删除了对应部分,并更新了各种对应的代码用例。
|
||||
* 新增 [没有外部名的构造器参数](../chapter2/14_Initialization.md#initializer-parameters-without-external-names) 章节。
|
||||
* 新增 [Required 构造器](../chapter2/14_Initialization.md#required-initializers) 章节。
|
||||
* 新增 [可选元组返回类型](../chapter2/06_Functions.md#optional-tuple-return-types) 章节。
|
||||
* 更新 [类型注解](../chapter2/01_TheBasics.md#type-annotations) 章节,多个相关变量可以用"类型注解”在同一行中声明为同一类型。
|
||||
* `@optional`, `@lazy`, `@final`, `@required` 等关键字被更新为 `optional`, `lazy`, `final`, `required` 参见 [声明修饰符](../chapter3/06_Declarations.md#declaration-modifiers)。
|
||||
* 更新整本书中关于 `..<` 的引用,从半闭区间改为了[半开区间](../chapter2/BasicOperators.md#half-open-range-operator)。
|
||||
* 更新了小节[读取和修改字典](../chapter2/CollectionTypes.md#accessing-and-modifying-a-dictionary): `Dictionary` 现在增加了一个 Boolean 型的属性:`isEmpty`。
|
||||
* 更新了整本书中有关 `..<` 的引用,从半闭区间改为了 [半开区间](../chapter2/BasicOperators.md#half-open-range-operator)。
|
||||
* 更新 [读取和修改字典](../chapter2/CollectionTypes.md#accessing-and-modifying-a-dictionary) 章节, `Dictionary` 现在增加了一个 Boolean 型的属性:`isEmpty`。
|
||||
* 解释了哪些字符(集)可被用来定义 [自定义操作符](../chapter2/26_Advanced_Operators.md#custom-operators)。
|
||||
* `nil` 和布尔运算中的 `true` 和 `false` 现在被定义为 [字面量](../chapter3/02_Lexical_Structure.md#literal)。
|
||||
* Swift 中的数组 (`Array`) 类型从现在起具备了完整的值语义。具体信息被更新到[集合的可变性](../chapter2/CollectionTypes.md#mutability-of-collections)和[数组](../chapter2/CollectionTypes.md#arrays)两小节,以反映这个新的变化。 此外,还解释了如何给 Strings, Arrays 和 Dictionaries 进行赋值和拷贝。
|
||||
* Swift 中的数组 (`Array`) 类型从现在起具备了完整的值语义。具体内容被更新到 [集合的可变性](../chapter2/CollectionTypes.md#mutability-of-collections) 和 [数组](../chapter2/CollectionTypes.md#arrays) 两小节,以反映这个新的变化。 此外,还解释了如何给 Strings, Arrays 和 Dictionaries 进行赋值和拷贝。
|
||||
* [数组类型速记语法](../chapter2/CollectionTypes.md#array-type-shorthand-syntax) 从 `SomeType []` 更新为 ` [SomeType]`。
|
||||
* 新增关于[字典类型的速记语法](../chapter2/CollectionTypes.md#dictionary-type-shorthand-syntax)的内容,现在书写格式为: `[KeyType: ValueType]`。
|
||||
* 加入新的小节:[字典键类型的哈希值](../chapter2/CollectionTypes.md#hash-values-for-set-types)。
|
||||
* 新增 [字典类型的速记语法](../chapter2/CollectionTypes.md#dictionary-type-shorthand-syntax) 章节,现在书写格式为: ` [KeyType: ValueType]`。
|
||||
* 新增 [字典键类型的哈希值](../chapter2/CollectionTypes.md#hash-values-for-set-types) 章节。
|
||||
* [闭包表达式](../chapter2/07_Closures.md#closure-expressions) 示例中使用新的全局函数 `sorted` 取代原先的全局函数 `sort` 去展示如何返回一个全新的数组。
|
||||
* 更新关于[结构体逐一成员构造器](../chapter2/14_Initialization.md#memberwise-initializers-for-structure-types)的描述:即使结构体的成员 `没有默认值`,逐一成员构造器也可以自动获得。
|
||||
* [半开区间运算符](../chapter2/BasicOperators.md#half-open-range-operator)由`..` 改为 `..<`。
|
||||
* 添加一个[泛型拓展](../chapter2/22_Generics.md#extending-a-generic-type)的示例。
|
||||
* 更新 [结构体逐一成员构造器](../chapter2/14_Initialization.md#memberwise-initializers-for-structure-types) 章节,即使结构体的成员 `没有默认值`,逐一成员构造器也可以自动获得。
|
||||
* [半开区间运算符](../chapter2/BasicOperators.md#half-open-range-operator) 中`..` 更新为 `..<`。
|
||||
* 新增 [泛型拓展](../chapter2/22_Generics.md#extending-a-generic-type) 的示例。
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -41,11 +41,11 @@ var x = 0.0, y = 0.0, z = 0.0
|
||||
>
|
||||
> 如果你的代码中有不需要改变的值,请使用 `let` 关键字将它声明为常量。只将需要改变的值声明为变量。
|
||||
|
||||
### 类型标注 {#type-annotations}
|
||||
### 类型注解 {#type-annotations}
|
||||
|
||||
当你声明常量或者变量的时候可以加上*类型标注(type annotation)*,说明常量或者变量中要存储的值的类型。如果要添加类型标注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称。
|
||||
当你声明常量或者变量的时候可以加上*类型注解(type annotation)*,说明常量或者变量中要存储的值的类型。如果要添加类型注解,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称。
|
||||
|
||||
这个例子给 `welcomeMessage` 变量添加了类型标注,表示这个变量可以存储 `String` 类型的值:
|
||||
这个例子给 `welcomeMessage` 变量添加了类型注解,表示这个变量可以存储 `String` 类型的值:
|
||||
|
||||
```swift
|
||||
var welcomeMessage: String
|
||||
@ -63,7 +63,7 @@ var welcomeMessage: String
|
||||
welcomeMessage = "Hello"
|
||||
```
|
||||
|
||||
你可以在一行中定义多个同样类型的变量,用逗号分割,并在最后一个变量名之后添加类型标注:
|
||||
你可以在一行中定义多个同样类型的变量,用逗号分割,并在最后一个变量名之后添加类型注解:
|
||||
|
||||
```swift
|
||||
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}
|
||||
|
||||
@ -481,7 +481,7 @@ print("The status message is \(http200Status.description)")
|
||||
|
||||
> 注意
|
||||
>
|
||||
> 元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组。请参考[类和结构体](./09_Classes_and_Structures.md)。
|
||||
> 当遇到一些相关值的简单分组时,元组是很有用的。元组不适合用来创建复杂的数据结构。如果你的数据结构比较复杂,不要使用元组,用类或结构体去建模。欲获得更多信息,请参考 [结构体和类](./09_Classes_and_Structures.md)。
|
||||
|
||||
## 可选类型 {#optionals}
|
||||
|
||||
|
||||
@ -106,11 +106,11 @@ Escaping all three quotes \"\"\"
|
||||
|
||||
### 扩展字符串分隔符 {#extended-string-delimiters}
|
||||
|
||||
您可以将字符串文字放在扩展分隔符中,这样字符串中的特殊字符将会被直接包含而非转义后的效果。将字符串放在引号(**"**)中并用数字符号(**#**)括起来。例如,打印字符串文字 **#"Line 1 \ nLine 2"#** 打印换行符转义序列(**\n**)而不是进行换行打印。
|
||||
您可以将字符串文字放在扩展分隔符中,这样字符串中的特殊字符将会被直接包含而非转义后的效果。将字符串放在引号(`"`)中并用数字符号(`#`)括起来。例如,打印字符串文字 `#"Line 1 \nLine 2"#` 会打印换行符转义序列(`\n`)而不是给文字换行。
|
||||
|
||||
如果需要字符串文字中字符的特殊效果,请匹配转义字符(**\\**)后面添加与起始位置个数相匹配的 **#** 符。 例如,如果您的字符串是 **#"Line 1 \ nLine 2"#** 并且您想要换行,则可以使用 **#“Line 1 \ #nLine 2”#** 来代替。 同样,**###"Line1 \ ### nLine2"###** 也可以实现换行效果。
|
||||
如果需要字符串文字中字符的特殊效果,请匹配转义字符(`\`)后面添加与起始位置个数相匹配的 `#` 符。 例如,如果您的字符串是 `#"Line 1 \nLine 2"#` 并且您想要换行,则可以使用 `#“Line 1 \#nLine 2”#` 来代替。 同样,`###"Line1 \###nLine2"###` 也可以实现换行效果。
|
||||
|
||||
扩展分隔符创建的字符串文字也可以是多行字符串文字。 您可以使用扩展分隔符在多行字符串中包含文本 **"""**,覆盖原有的结束文字的默认行为。例如:
|
||||
扩展分隔符创建的字符串文字也可以是多行字符串文字。 您可以使用扩展分隔符在多行字符串中包含文本 `"""`,覆盖原有的结束文字的默认行为。例如:
|
||||
|
||||
```swift
|
||||
let threeMoreDoubleQuotationMarks = #"""
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
# 集合类型
|
||||
|
||||
Swift 语言提供 `Arrays`、`Sets` 和 `Dictionaries` 三种基本的*集合类型*用来存储集合数据。数组(Arrays)是有序数据的集。集合(Sets)是无序无重复数据的集。字典(Dictionaries)是无序的键值对的集。
|
||||
Swift 语言提供数组(Array)、集合(Set)和字典(Dictionary)三种基本的*集合类型*用来存储集合数据。数组是有序数据的集。集合是无序无重复数据的集。字典是无序的键值对的集。
|
||||
|
||||

|
||||
|
||||
Swift 语言中的 `Arrays`、`Sets` 和 `Dictionaries` 中存储的数据值类型必须明确。这意味着我们不能把错误的数据类型插入其中。同时这也说明你完全可以对取回值的类型非常放心。
|
||||
Swift 中的数组、集合和字典必须明确其中保存的键和值类型,这样就可以避免插入一个错误数据类型的值。同理,对于获取到的值你也可以放心,其数据类型是确定的。
|
||||
|
||||
> 注意
|
||||
>
|
||||
> Swift 的 `Arrays`、`Sets` 和 `Dictionaries` 类型被实现为*泛型集合*。更多关于泛型类型和集合,参见 [泛型](./23_Generics.md)章节。
|
||||
> Swift 的数组、集合和字典类型被实现为*泛型集合*。更多关于泛型类型和集合,参见 [泛型](./22_Generics.md) 章节。
|
||||
|
||||
## 集合的可变性 {#mutability-of-collections}
|
||||
|
||||
如果创建一个 `Arrays`、`Sets` 或 `Dictionaries` 并且把它分配成一个变量,这个集合将会是*可变的*。这意味着你可以在创建之后添加更多或移除已存在的数据项,或者改变集合中的数据项。如果我们把 `Arrays`、`Sets` 或 `Dictionaries` 分配成常量,那么它就是*不可变的*,它的大小和内容都不能被改变。
|
||||
如果创建一个数组、集合或字典并且把它分配成一个变量,这个集合将会是*可变的*。这意味着可以在创建之后添加、修改或者删除数据项。如果把数组、集合或字典分配成常量,那么它就是*不可变的*,它的大小和内容都不能被改变。
|
||||
|
||||
> 注意
|
||||
>
|
||||
> 在我们不需要改变集合的时候创建不可变集合是很好的实践。如此 Swift 编译器可以优化我们创建的集合。
|
||||
> 在不需要改变集合的时候创建不可变集合是很好的实践。这样做便于你理解自己的代码,也能让 Swift 编译器优化集合的性能。
|
||||
|
||||
## 数组(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}
|
||||
|
||||
写 Swift 数组应该遵循像 `Array<Element>` 这样的形式,其中 `Element` 是这个数组中唯一允许存在的数据类型。我们也可以使用像 `[Element]` 这样的简单语法。尽管两种形式在功能上是一样的,但是推荐较短的那种,而且在本文中都会使用这种形式来使用数组。
|
||||
Swift 中数组的完整写法为 `Array<Element>`,其中 `Element` 是这个数组中唯一允许存在的数据类型。也可以使用像 `[Element]` 这样的简单语法。尽管两种形式在功能上是一样的,但是推荐较短的那种,而且在本文中都会使用这种形式来使用数组。
|
||||
|
||||
### 创建一个空数组 {#creating-an-empty-array}
|
||||
|
||||
我们可以使用构造语法来创建一个由特定数据类型构成的空数组:
|
||||
你可以使用构造语法来创建一个由特定数据类型构成的空数组:
|
||||
|
||||
```swift
|
||||
var someInts = [Int]()
|
||||
@ -42,7 +44,7 @@ print("someInts is of type [Int] with \(someInts.count) items.")
|
||||
|
||||
注意,通过构造函数的类型,`someInts` 的值类型被推断为 `[Int]`。
|
||||
|
||||
或者,如果代码上下文中已经提供了类型信息,例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:`[]`(一对空方括号):
|
||||
或者,如果代码上下文中已经提供了类型信息,例如一个函数参数或者一个已经定义好类型的常量或者变量,你可以使用空数组语句创建一个空数组,它的写法很简单:`[]`(一对空方括号):
|
||||
|
||||
```swift
|
||||
someInts.append(3)
|
||||
@ -53,7 +55,7 @@ someInts = []
|
||||
|
||||
### 创建一个带有默认值的数组 {#creating-an-array-with-a-default-value}
|
||||
|
||||
Swift 中的 `Array` 类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量(`count`)和适当类型的初始值(`repeating`)传入数组构造函数:
|
||||
Swift 中的 `Array` 类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。可以把准备加入新数组的数据项数量(`count`)和适当类型的初始值(`repeating`)传入数组构造函数:
|
||||
|
||||
```swift
|
||||
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}
|
||||
|
||||
我们可以使用加法操作符(`+`)来组合两种已存在的相同类型数组。新数组的数据类型会被从两个数组的数据类型中推断出来:
|
||||
你可以使用加法操作符(`+`)来组合两个已存在的相同类型数组。新数组的数据类型会从两个数组的数据类型中推断出来:
|
||||
|
||||
```swift
|
||||
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
|
||||
@ -74,7 +76,7 @@ var sixDoubles = threeDoubles + anotherThreeDoubles
|
||||
|
||||
### 用数组字面量构造数组 {#creating-an-array-with-an-array-literals}
|
||||
|
||||
我们可以使用*数组字面量*来进行数组构造,这是一种用一个或者多个数值构造数组的简单方法。数组字面量是一系列由逗号分割并由方括号包含的数值:
|
||||
你可以使用*数组字面量*来进行数组构造,这是一种用一个或者多个数值构造数组的简单方法。数组字面量是一系列由逗号分割并由方括号包含的数值:
|
||||
|
||||
`[value 1, value 2, value 3]`。
|
||||
|
||||
@ -89,11 +91,11 @@ var shoppingList: [String] = ["Eggs", "Milk"]
|
||||
|
||||
> 注意
|
||||
>
|
||||
> `shoppingList` 数组被声明为变量(`var` 关键字创建)而不是常量(`let` 创建)是因为以后可能会有更多的数据项被插入其中。
|
||||
> `shoppingList` 数组被声明为变量(`var` 关键字创建)而不是常量(`let` 创建)是因为之后会有更多的数据项被插入其中。
|
||||
|
||||
在这个例子中,字面量仅仅包含两个 `String` 值。匹配了该数组的变量声明(只能包含 `String` 的数组),所以这个字面量的分配过程可以作为用两个初始项来构造 `shoppingList` 的一种方式。
|
||||
在这个例子中,字面量仅仅包含两个 `String` 值。匹配了该数组的声明(只能包含 `String` 的数组),所以可以将这个字面量的赋值过程看作用两个初始项来构造 `shoppingList` 的一种方式。
|
||||
|
||||
由于 Swift 的类型推断机制,当我们用字面量构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。`shoppingList` 的构造也可以这样写:
|
||||
由于 Swift 的类型推断机制,当你用字面量构造拥有相同类型值数组的时候,不必把数组的类型定义清楚。`shoppingList` 的构造也可以这样写:
|
||||
|
||||
```swift
|
||||
var shoppingList = ["Eggs", "Milk"]
|
||||
@ -103,7 +105,7 @@ var shoppingList = ["Eggs", "Milk"]
|
||||
|
||||
### 访问和修改数组 {#accessing-and-modifying-an-array}
|
||||
|
||||
我们可以通过数组的方法和属性来访问和修改数组,或者使用下标语法。
|
||||
你可以通过数组的方法和属性来访问和修改数组,或者使用下标语法。
|
||||
|
||||
可以使用数组的只读属性 `count` 来获取数组中的数据项数量:
|
||||
|
||||
@ -127,10 +129,10 @@ if shoppingList.isEmpty {
|
||||
|
||||
```swift
|
||||
shoppingList.append("Flour")
|
||||
// shoppingList 现在有3个数据项,有人在摊煎饼
|
||||
// shoppingList 现在有3个数据项,似乎有人在摊煎饼
|
||||
```
|
||||
|
||||
除此之外,使用加法赋值运算符(`+=`)也可以直接在数组后面添加一个或多个拥有相同类型的数据项:
|
||||
除此之外,也可以使用加法赋值运算符(`+=`)直接将另一个相同类型数组中的数据添加到该数组后面:
|
||||
|
||||
```swift
|
||||
shoppingList += ["Baking Powder"]
|
||||
@ -139,7 +141,7 @@ shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
|
||||
// shoppingList 现在有七项了
|
||||
```
|
||||
|
||||
可以直接使用下标语法来获取数组中的数据项,把我们需要的数据项的索引值放在直接放在数组名称的方括号中:
|
||||
可以直接使用*下标语法*来获取数组中的数据项,把所需要数据项的索引值直接放在数组名称之后的方括号中:
|
||||
|
||||
```swift
|
||||
var firstItem = shoppingList[0]
|
||||
@ -150,13 +152,15 @@ var firstItem = shoppingList[0]
|
||||
>
|
||||
> 第一项在数组中的索引值是 `0` 而不是 `1`。 Swift 中的数组索引总是从零开始。
|
||||
|
||||
我们也可以用下标来改变某个已有索引值对应的数据值:
|
||||
你也可以用下标来改变某个有效索引值对应的数据值:
|
||||
|
||||
```swift
|
||||
shoppingList[0] = "Six eggs"
|
||||
// 其中的第一项现在是“Six eggs”而不是“Eggs”
|
||||
```
|
||||
|
||||
当你使用下标语法,所使用的下标必须是有效的。例如,试图通过 `shoppingList[shoppingList.count] = "Salt"` 在数组的最后添加一项,将产生一个运行时错误。
|
||||
|
||||
还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把 `"Chocolate Spread"`、`"Cheese"` 和 `"Butter"` 替换为 `"Bananas"` 和 `"Apples"`:
|
||||
|
||||
```swift
|
||||
@ -164,11 +168,7 @@ shoppingList[4...6] = ["Bananas", "Apples"]
|
||||
// shoppingList 现在有6项
|
||||
```
|
||||
|
||||
> 注意
|
||||
>
|
||||
> 不可以用下标访问的形式去在数组尾部添加新项。
|
||||
|
||||
调用数组的 `insert(_:at:)` 方法来在某个具体索引值之前添加数据项:
|
||||
通过调用数组的 `insert(_:at:)` 方法在某个指定索引值之前添加数据项:
|
||||
|
||||
```swift
|
||||
shoppingList.insert("Maple Syrup", at: 0)
|
||||
@ -178,18 +178,18 @@ shoppingList.insert("Maple Syrup", at: 0)
|
||||
|
||||
这次 `insert(_:at:)` 方法调用把值为 `"Maple Syrup"` 的新数据项插入列表的最开始位置,并且使用 `0` 作为索引值。
|
||||
|
||||
类似的我们可以使用 `remove(at:)` 方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(我们不需要的时候就可以无视它):
|
||||
类似的可以使用 `remove(at:)` 方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(不需要的时候就可以无视它):
|
||||
|
||||
```swift
|
||||
let mapleSyrup = shoppingList.remove(at: 0)
|
||||
// 索引值为0的数据项被移除
|
||||
// shoppingList 现在只有6项,而且不包括 Maple Syrup
|
||||
// mapleSyrup 常量的值等于被移除数据项“Maple Syrup”的值
|
||||
// mapleSyrup 常量的值等于被移除数据项“Maple Syrup”
|
||||
```
|
||||
|
||||
> 注意
|
||||
>
|
||||
> 如果我们试着对索引越界的数据进行检索或者设置新值的操作,会引发一个运行期错误。我们可以使用索引值和数组的 `count` 属性进行比较来在使用某个索引之前先检验是否有效。除了当 `count` 等于 0 时(说明这是个空数组),最大索引值一直是 `count - 1`,因为数组都是零起索引。
|
||||
> 如果你试图通过越界索引来执行访问或者修改数据的操作,会引发一个运行时错误。此时可以使用索引值和数组的 `count` 属性进行比较来在使用该索引之前检验其是否有效。除了当 `count` 等于 0 时(说明这是个空数组),最大索引值一直是 `count - 1`,因为数组都是零起索引。
|
||||
|
||||
数据项被移除后数组中的空出项会被自动填补,所以现在索引值为 `0` 的数据项的值再次等于 `"Six eggs"`:
|
||||
|
||||
@ -198,18 +198,18 @@ firstItem = shoppingList[0]
|
||||
// firstItem 现在等于“Six eggs”
|
||||
```
|
||||
|
||||
如果我们只想把数组中的最后一项移除,可以使用 `removeLast()` 方法而不是 `remove(at:)` 方法来避免我们需要获取数组的 `count` 属性。就像后者一样,前者也会返回被移除的数据项:
|
||||
如果你只想把数组中的最后一项移除,可以使用 `removeLast()` 方法而不是 `remove(at:)` 方法来避免需要获取数组的 `count` 属性。就像后者一样,前者也会返回被移除的数据项:
|
||||
|
||||
```swift
|
||||
let apples = shoppingList.removeLast()
|
||||
// 数组的最后一项被移除了
|
||||
// shoppingList 现在只有5项,不包括 Apples
|
||||
// apples 常量的值现在等于“Apples”字符串
|
||||
// apples 常量的值现在等于字符串“Apples”
|
||||
```
|
||||
|
||||
### 数组的遍历 {#iterating-over-an-array}
|
||||
|
||||
我们可以使用 `for-in` 循环来遍历所有数组中的数据项:
|
||||
你可以使用 `for-in` 循环来遍历数组中所有的数据项:
|
||||
|
||||
```swift
|
||||
for item in shoppingList {
|
||||
@ -222,7 +222,7 @@ for item in shoppingList {
|
||||
// Bananas
|
||||
```
|
||||
|
||||
如果我们同时需要每个数据项的值和索引值,可以使用 `enumerated()` 方法来进行数组遍历。`enumerated()` 返回一个由每一个数据项索引值和数据值组成的元组。我们可以把这个元组分解成临时常量或者变量来进行遍历:
|
||||
如果同时需要每个数据项的值和索引值,可以使用 `enumerated()` 方法来进行数组遍历。`enumerated()` 返回一个由索引值和数据值组成的元组数组。索引值从零开始,并且每次增加一;如果枚举一整个数组,索引值将会和数据值一一匹配。你可以把这个元组分解成临时常量或者变量来进行遍历:
|
||||
|
||||
```swift
|
||||
for (index, value) in shoppingList.enumerated() {
|
||||
@ -235,38 +235,38 @@ for (index, value) in shoppingList.enumerated() {
|
||||
// Item 5: Bananas
|
||||
```
|
||||
|
||||
更多关于 `for-in` 循环的介绍请参见[for 循环](05_Control_Flow.html#for_loops)。
|
||||
更多关于 `for-in` 循环的介绍请参见 [For 循环](05_Control_Flow.html#for_loops)。
|
||||
|
||||
## 集合(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}
|
||||
|
||||
一个类型为了存储在集合中,该类型必须是*可哈希化*的——也就是说,该类型必须提供一个方法来计算它的*哈希值*。一个哈希值是 `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` 三个值来说,`==` 的实现必须满足下面三种情况:
|
||||
|
||||
> * `a == a`(自反性)
|
||||
> * `a == b` 意味着 `b == a`(对称性)
|
||||
> * `a == b && b == c` 意味着 `a == c`(传递性)
|
||||
|
||||
关于遵循协议的更多信息,请看[协议](./22_Protocols.md)。
|
||||
>
|
||||
> 关于遵循协议的更多信息,请看 [协议](./21_Protocols.md)。
|
||||
|
||||
### 集合类型语法 {#set-type-syntax}
|
||||
|
||||
Swift 中的 `Set` 类型被写为 `Set<Element>`,这里的 `Element` 表示 `Set` 中允许存储的类型,和数组不同的是,集合没有等价的简化形式。
|
||||
Swift 中的集合类型被写为 `Set<Element>`,这里的 `Element` 表示集合中允许存储的类型。和数组不同的是,集合没有等价的简化形式。
|
||||
|
||||
### 创建和构造一个空的集合 {#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
|
||||
letters.insert("a")
|
||||
@ -293,7 +293,7 @@ letters = []
|
||||
|
||||
### 用数组字面量创建集合 {#creating-a-set-with-an-array-literal}
|
||||
|
||||
你可以使用数组字面量来构造集合,并且可以使用简化形式写一个或者多个值作为集合元素。
|
||||
你可以使用数组字面量来构造集合,相当于一种简化的形式将一个或者多个值作为集合元素。
|
||||
|
||||
下面的例子创建一个称之为 `favoriteGenres` 的集合来存储 `String` 类型的值:
|
||||
|
||||
@ -302,13 +302,13 @@ var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
|
||||
// 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
|
||||
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
|
||||
@ -318,9 +318,9 @@ var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
|
||||
|
||||
### 访问和修改一个集合 {#accesing-and-modifying-a-set}
|
||||
|
||||
你可以通过 `Set` 的属性和方法来访问和修改一个 `Set`。
|
||||
你可以通过集合的属性和方法来对其进行访问和修改。
|
||||
|
||||
为了找出一个 `Set` 中元素的数量,可以使用其只读属性 `count`:
|
||||
为了获取一个集合中元素的数量,可以使用其只读属性 `count`:
|
||||
|
||||
```swift
|
||||
print("I have \(favoriteGenres.count) favorite music genres.")
|
||||
@ -338,14 +338,14 @@ if favoriteGenres.isEmpty {
|
||||
// 打印“I have particular music preferences.”
|
||||
```
|
||||
|
||||
你可以通过调用 `Set` 的 `insert(_:)` 方法来添加一个新元素:
|
||||
你可以通过调用集合的 `insert(_:)` 方法来添加一个新元素:
|
||||
|
||||
```swift
|
||||
favoriteGenres.insert("Jazz")
|
||||
// favoriteGenres 现在包含4个元素
|
||||
```
|
||||
|
||||
你可以通过调用 `Set` 的 `remove(_:)` 方法去删除一个元素,如果该值是该 `Set` 的一个元素则删除该元素并且返回被删除的元素值,否则如果该 `Set` 不包含该值,则返回 `nil`。另外,`Set` 中的所有元素可以通过它的 `removeAll()` 方法删除。
|
||||
你可以通过调用集合的 `remove(_:)` 方法去删除一个元素,如果它是该集合的一个元素则删除它并且返回它的值,若该集合不包含它,则返回 `nil`。另外,集合可以通过 `removeAll()` 方法删除所有元素。
|
||||
|
||||
```swift
|
||||
if let removedGenre = favoriteGenres.remove("Rock") {
|
||||
@ -356,7 +356,7 @@ if let removedGenre = favoriteGenres.remove("Rock") {
|
||||
// 打印“Rock? I'm over it.”
|
||||
```
|
||||
|
||||
使用 `contains(_:)` 方法去检查 `Set` 中是否包含一个特定的值:
|
||||
使用 `contains(_:)` 方法去检查集合中是否包含一个特定的值:
|
||||
|
||||
```swift
|
||||
if favoriteGenres.contains("Funk") {
|
||||
@ -369,7 +369,7 @@ if favoriteGenres.contains("Funk") {
|
||||
|
||||
### 遍历一个集合 {#iterating-over-a-set}
|
||||
|
||||
你可以在一个 `for-in` 循环中遍历一个 `Set` 中的所有值。
|
||||
你可以在一个 `for-in` 循环中遍历一个集合中的所有值。
|
||||
|
||||
```swift
|
||||
for genre in favoriteGenres {
|
||||
@ -382,7 +382,7 @@ for genre in favoriteGenres {
|
||||
|
||||
更多关于 `for-in` 循环的信息,参见 [For 循环](./05_Control_Flow.md#for_loops)。
|
||||
|
||||
Swift 的 `Set` 类型没有确定的顺序,为了按照特定顺序来遍历一个 `Set` 中的值可以使用 `sorted()` 方法,它将返回一个有序数组,这个数组的元素排列顺序由操作符'<'对元素进行比较的结果来确定。
|
||||
Swift 的 `Set` 类型没有确定的顺序,为了按照特定顺序来遍历一个集合中的值可以使用 `sorted()` 方法,它将返回一个有序数组,这个数组的元素排列顺序由操作符 `<` 对元素进行比较的结果来确定。
|
||||
|
||||
```swift
|
||||
for genre in favoriteGenres.sorted() {
|
||||
@ -395,7 +395,7 @@ for genre in favoriteGenres.sorted() {
|
||||
|
||||
## 集合操作 {#performing-set-operations}
|
||||
|
||||
你可以高效地完成 `Set` 的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交。
|
||||
你可以高效地完成集合的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交。
|
||||
|
||||
### 基本集合操作 {#fundamental-set-operations}
|
||||
|
||||
@ -403,10 +403,10 @@ for genre in favoriteGenres.sorted() {
|
||||
|
||||

|
||||
|
||||
* 使用 `intersection(_:)` 方法根据两个集合中都包含的值创建的一个新的集合。
|
||||
* 使用 `symmetricDifference(_:)` 方法根据在一个集合中但不在两个集合中的值创建一个新的集合。
|
||||
* 使用 `union(_:)` 方法根据两个集合的值创建一个新的集合。
|
||||
* 使用 `subtracting(_:)` 方法根据不在该集合中的值创建一个新的集合。
|
||||
* 使用 `intersection(_:)` 方法根据两个集合的交集创建一个新的集合。
|
||||
* 使用 `symmetricDifference(_:)` 方法根据两个集合不相交的值创建一个新的集合。
|
||||
* 使用 `union(_:)` 方法根据两个集合的所有值创建一个新的集合。
|
||||
* 使用 `subtracting(_:)` 方法根据不在另一个集合中的值创建一个新的集合。
|
||||
|
||||
```swift
|
||||
let oddDigits: Set = [1, 3, 5, 7, 9]
|
||||
@ -425,13 +425,13 @@ oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
|
||||
|
||||
### 集合成员关系和相等 {#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` 是*不相交*的,因为它们之间没有共同的元素。
|
||||
|
||||

|
||||
|
||||
* 使用“是否相等”运算符(`==`)来判断两个集合是否包含全部相同的值。
|
||||
* 使用 `isSubset(of:)` 方法来判断一个集合中的值是否也被包含在另外一个集合中。
|
||||
* 使用 `isSuperset(of:)` 方法来判断一个集合中包含另一个集合中所有的值。
|
||||
* 使用“是否相等”运算符(`==`)来判断两个集合包含的值是否全部相同。
|
||||
* 使用 `isSubset(of:)` 方法来判断一个集合中的所有值是否也被包含在另外一个集合中。
|
||||
* 使用 `isSuperset(of:)` 方法来判断一个集合是否包含另一个集合中所有的值。
|
||||
* 使用 `isStrictSubset(of:)` 或者 `isStrictSuperset(of:)` 方法来判断一个集合是否是另外一个集合的子集合或者父集合并且两个集合并不相等。
|
||||
* 使用 `isDisjoint(with:)` 方法来判断两个集合是否不含有相同的值(是否没有交集)。
|
||||
|
||||
@ -450,27 +450,27 @@ farmAnimals.isDisjoint(with: cityAnimals)
|
||||
|
||||
## 字典 {#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}
|
||||
|
||||
Swift 的字典使用 `Dictionary<Key, Value>` 定义,其中 `Key` 是字典中键的数据类型,`Value` 是字典中对应于这些键所存储值的数据类型。
|
||||
Swift 的字典使用 `Dictionary<Key, Value>` 定义,其中 `Key` 是一种可以在字典中被用作键的类型,`Value` 是字典中对应于这些键所存储值的数据类型。
|
||||
|
||||
> 注意
|
||||
>
|
||||
> 一个字典的 `Key` 类型必须遵循 `Hashable` 协议,就像 `Set` 的值类型。
|
||||
|
||||
我们也可以用 `[Key: Value]` 这样简化的形式去创建一个字典类型。虽然这两种形式功能上相同,但是后者是首选,并且这本指导书涉及到字典类型时通篇采用后者。
|
||||
你也可以用 `[Key: Value]` 这样简化的形式去表示字典类型。虽然这两种形式功能上相同,但是后者是首选,并且本教程中涉及到字典类型时通篇采用后者。
|
||||
|
||||
### 创建一个空字典 {#creating-an-empty-dictionary}
|
||||
|
||||
我们可以像数组一样使用构造语法创建一个拥有确定类型的空字典:
|
||||
你可以像数组一样使用构造语法创建一个拥有确定类型的空字典:
|
||||
|
||||
```swift
|
||||
var namesOfIntegers = [Int: String]()
|
||||
@ -479,7 +479,7 @@ var namesOfIntegers = [Int: String]()
|
||||
|
||||
这个例子创建了一个 `[Int: String]` 类型的空字典来储存整数的英语命名。它的键是 `Int` 型,值是 `String` 型。
|
||||
|
||||
如果上下文已经提供了类型信息,我们可以使用空字典字面量来创建一个空字典,记作 `[:]`(中括号中放一个冒号):
|
||||
如果上下文已经提供了类型信息,你可以使用空字典字面量来创建一个空字典,记作 `[:]` (一对方括号中放一个冒号):
|
||||
|
||||
```swift
|
||||
namesOfIntegers[16] = "sixteen"
|
||||
@ -490,9 +490,9 @@ namesOfIntegers = [:]
|
||||
|
||||
### 用字典字面量创建字典 {#creating-a-dictionary-with-a-dictionary-literal}
|
||||
|
||||
我们可以使用*字典字面量*来构造字典,这和我们刚才介绍过的数组字面量拥有相似语法。字典字面量是一种将一个或多个键值对写作 `Dictionary` 集合的快捷途径。
|
||||
你可以使用*字典字面量*来构造字典,这和刚才介绍过的数组字面量拥有相似语法。字典字面量是一种将一个或多个键值对写作 `Dictionary` 集合的快捷途径。
|
||||
|
||||
一个键值对是一个 `key` 和一个 `value` 的结合体。在字典字面量中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含、由逗号分割:
|
||||
*一个键值对*是一个键和一个值的结合体。在字典字面量中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由逗号分割、并整体被包裹在一对方括号中:
|
||||
|
||||
```swift
|
||||
[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`。
|
||||
|
||||
这个字典语句包含了两个 `String: String` 类型的键值对。它们对应 `airports` 变量声明的类型(一个只有 `String` 键和 `String` 值的字典)所以这个字典字面量的任务是构造拥有两个初始数据项的 `airport` 字典。
|
||||
这个字典语句包含了两个 `String: String` 类型的键值对。它们对应 `airports` 变量声明的类型(一个只有 `String` 键和 `String` 值的字典),所以这个字典字面量的赋值是一种方式用来构造拥有两个初始数据项的 `airport` 字典。
|
||||
|
||||
和数组一样,我们在用字典字面量构造字典时,如果它的键和值都有各自一致的类型,那么就不必写出字典的类型。
|
||||
和数组一样,你在用字典字面量构造字典时,如果它的键和值都有各自一致的类型,那么就不必写出字典的类型。
|
||||
`airports` 字典也可以用这种简短方式定义:
|
||||
|
||||
```swift
|
||||
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
|
||||
```
|
||||
|
||||
因为这个语句中所有的键和值都各自拥有相同的数据类型,Swift 可以推断出 `Dictionary<String, String>` 是 `airports` 字典的正确类型。
|
||||
因为这个语句中所有的键和值都各自拥有相同的数据类型,Swift 可以推断出 `[String: String]` 是 `airports` 字典的正确类型。
|
||||
|
||||
### 访问和修改字典 {#accessing-and-modifying-a-dictionary}
|
||||
|
||||
我们可以通过字典的方法和属性来访问和修改字典,或者通过使用下标语法。
|
||||
你可以通过字典的方法和属性来访问和修改字典,或者通过使用下标语法。
|
||||
|
||||
和数组一样,我们可以通过字典的只读属性 `count` 来获取某个字典的数据项数量:
|
||||
和数组一样,可以通过 `Dictionary` 的只读属性 `count` 来获取字典的数据项数量:
|
||||
|
||||
```swift
|
||||
print("The dictionary of airports contains \(airports.count) items.")
|
||||
@ -545,25 +545,23 @@ if airports.isEmpty {
|
||||
// 打印“The airports dictionary is not empty.”
|
||||
```
|
||||
|
||||
我们也可以在字典中使用下标语法来添加新的数据项。可以使用一个恰当类型的键作为下标索引,并且分配恰当类型的新值:
|
||||
你可以通过下标语法来给字典添加新的数据项。可以使用一个恰当类型的键作为下标索引,并且分配恰当类型的新值:
|
||||
|
||||
```swift
|
||||
airports["LHR"] = "London"
|
||||
// airports 字典现在有三个数据项
|
||||
```
|
||||
|
||||
我们也可以使用下标语法来改变特定键对应的值:
|
||||
也可以使用下标语法来改变特定键对应的值:
|
||||
|
||||
```swift
|
||||
airports["LHR"] = "London Heathrow"
|
||||
// “LHR”对应的值被改为“London Heathrow”
|
||||
```
|
||||
|
||||
作为另一种下标方法,字典的 `updateValue(_:forKey:)` 方法可以设置或者更新特定键对应的值。就像上面所示的下标示例,`updateValue(_:forKey:)` 方法在这个键不存在对应值的时候会设置新值或者在存在时更新已存在的值。和上面的下标方法不同的,`updateValue(_:forKey:)` 这个方法返回更新值之前的原值。这样使得我们可以检查更新是否成功。
|
||||
作为一种替代下标语法的方式,字典的 `updateValue(_:forKey:)` 方法可以设置或者更新特定键对应的值。就像上面所示的下标示例,`updateValue(_:forKey:)` 方法在这个键不存在对应值的时候会设置新值或者在存在时更新已存在的值。和下标的方式不同,`updateValue(_:forKey:)` 这个方法返回更新值之前的*原值*。这样使得你可以检查更新是否成功。
|
||||
|
||||
`updateValue(_:forKey:)` 方法会返回对应值的类型的可选值。举例来说:对于存储 `String` 值的字典,这个函数会返回一个 `String?` 或者“可选 `String`”类型的值。
|
||||
|
||||
如果有值存在于更新前,则这个可选值包含了旧值,否则它将会是 `nil`。
|
||||
`updateValue(_:forKey:)` 方法会返回对应值类型的可选类型。举例来说:对于存储 `String` 值的字典,这个函数会返回一个 `String?` 或者“可选 `String`”类型的值。如果有值存在于更新前,则这个可选值包含了旧值,否则它将会是 `nil` :
|
||||
|
||||
```swift
|
||||
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.”
|
||||
```
|
||||
|
||||
我们也可以使用下标语法来在字典中检索特定键对应的值。因为有可能请求的键没有对应的值存在,字典的下标访问会返回对应值的类型的可选值。如果这个字典包含请求键所对应的值,下标会返回一个包含这个存在值的可选值,否则将返回 `nil`:
|
||||
你也可以使用下标语法来在字典中检索特定键对应的值。因为有可能请求的键没有对应的值存在,字典的下标访问会返回对应值类型的可选类型。如果这个字典包含请求键所对应的值,下标会返回一个包含这个存在值的可选类型,否则将返回 `nil`:
|
||||
|
||||
```swift
|
||||
if let airportName = airports["DUB"] {
|
||||
@ -583,7 +581,7 @@ if let airportName = airports["DUB"] {
|
||||
// 打印“The name of the airport is Dublin Airport.”
|
||||
```
|
||||
|
||||
我们还可以使用下标语法来通过给某个键的对应值赋值为 `nil` 来从字典里移除一个键值对:
|
||||
还可以使用下标语法通过将某个键的对应值赋值为 `nil` 来从字典里移除一个键值对:
|
||||
|
||||
```swift
|
||||
airports["APL"] = "Apple Internation"
|
||||
@ -592,7 +590,7 @@ airports["APL"] = nil
|
||||
// APL 现在被移除了
|
||||
```
|
||||
|
||||
此外,`removeValue(forKey:)` 方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的值或者在没有值的情况下返回 `nil`:
|
||||
此外,`removeValue(forKey:)` 方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的值或者在没有对应值的情况下返回 `nil`:
|
||||
|
||||
```swift
|
||||
if let removedValue = airports.removeValue(forKey: "DUB") {
|
||||
@ -605,7 +603,7 @@ if let removedValue = airports.removeValue(forKey: "DUB") {
|
||||
|
||||
### 字典遍历 {#iterating-over-a-dictionary}
|
||||
|
||||
我们可以使用 `for-in` 循环来遍历某个字典中的键值对。每一个字典中的数据项都以 `(key, value)` 元组形式返回,并且我们可以使用临时常量或者变量来分解这些元组:
|
||||
你可以使用 `for-in` 循环来遍历某个字典中的键值对。每一个字典中的数据项都以 `(key, value)` 元组形式返回,并且可以使用临时常量或者变量来分解这些元组:
|
||||
|
||||
```swift
|
||||
for (airportCode, airportName) in airports {
|
||||
@ -617,7 +615,7 @@ for (airportCode, airportName) in airports {
|
||||
|
||||
更多关于 `for-in` 循环的信息,参见 [For 循环](./05_Control_Flow.md#for_loops)。
|
||||
|
||||
通过访问 `keys` 或者 `values` 属性,我们也可以遍历字典的键或者值:
|
||||
通过访问 `keys` 或者 `values` 属性,你也可以遍历字典的键或者值:
|
||||
|
||||
```swift
|
||||
for airportCode in airports.keys {
|
||||
@ -633,7 +631,7 @@ for airportName in airports.values {
|
||||
// Airport name: London Heathrow
|
||||
```
|
||||
|
||||
如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受 `Array` 实例的 API 的参数,可以直接使用 `keys` 或者 `values` 属性构造一个新数组:
|
||||
如果你需要使用某个字典的键集合或者值集合来作为某个接受 `Array` 实例的 API 的参数,可以直接使用 `keys` 或者 `values` 属性构造一个新数组:
|
||||
|
||||
```swift
|
||||
let airportCodes = [String](airports.keys)
|
||||
@ -643,4 +641,4 @@ let airportNames = [String](airports.values)
|
||||
// airportNames 是 ["Toronto Pearson", "London Heathrow"]
|
||||
```
|
||||
|
||||
Swift 的字典类型是无序集合类型。为了以特定的顺序遍历字典的键或值,可以对字典的 `keys` 或 `values` 属性使用 `sorted()` 方法。
|
||||
Swift 的 `Dictionary` 是无序集合类型。为了以特定的顺序遍历字典的键或值,可以对字典的 `keys` 或 `values` 属性使用 `sorted()` 方法。
|
||||
|
||||
@ -30,9 +30,9 @@ let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
|
||||
for (animalName, legCount) in numberOfLegs {
|
||||
print("\(animalName)s have \(legCount) legs")
|
||||
}
|
||||
// cats have 4 legs
|
||||
// ants have 6 legs
|
||||
// spiders have 8 legs
|
||||
// cats have 4 legs
|
||||
```
|
||||
|
||||
字典的内容理论上是无序的,遍历元素时的顺序是无法确定的。将元素插入字典的顺序并不会决定它们被遍历的顺序。关于数组和字典的细节,参见 [集合类型](./04_Collection_Types.md)。
|
||||
@ -324,7 +324,7 @@ default:
|
||||
// 输出“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}
|
||||
|
||||
|
||||
@ -202,6 +202,30 @@ if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
|
||||
// 打印“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}
|
||||
|
||||
每个函数参数都有一个*参数标签(argument label)*以及一个*参数名称(parameter name)*。参数标签在调用函数的时候使用;调用的时候需要将函数的参数标签写在对应的参数前面。参数名称在函数的实现中使用。默认情况下,函数参数使用参数名称来作为它们的参数标签。
|
||||
|
||||
@ -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`),以便和类型名区分。
|
||||
|
||||
以下是定义结构体和定义类的示例:
|
||||
|
||||
|
||||
@ -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}
|
||||
|
||||
只有 getter 没有 setter 的计算属性叫*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。
|
||||
|
||||
@ -157,7 +157,7 @@ ovenLight.next()
|
||||
|
||||
## 类型方法 {#type-methods}
|
||||
|
||||
实例方法是被某个类型的实例调用的方法。你也可以定义在类型本身上调用的方法,这种方法就叫做*类型方法*。在方法的 `func` 关键字之前加上关键字 `static`,来指定类型方法。类还可以用关键字 `class` 来允许子类重写父类的方法实现。
|
||||
实例方法是被某个类型的实例调用的方法。你也可以定义在类型本身上调用的方法,这种方法就叫做*类型方法*。在方法的 `func` 关键字之前加上关键字 `static`,来指定类型方法。类还可以用关键字 `class` 来指定,从而允许子类重写父类该方法的实现。
|
||||
|
||||
> 注意
|
||||
>
|
||||
|
||||
@ -72,7 +72,7 @@ numberOfLegs["bird"] = 2
|
||||
|
||||
## 下标选项 {#subscript-options}
|
||||
|
||||
下标可以接受任意数量的入参,并且这些入参可以是任意类型。下标的返回值也可以是任意类型。下标可以使用变量参数和可变参数,但不能使用输入输出参数,也不能给参数设置默认值。
|
||||
下标可以接受任意数量的入参,并且这些入参可以是任意类型。下标的返回值也可以是任意类型。下标可以使用可变参数,并且可以提供默认参数数值,但是不能使用输入输出参数。
|
||||
|
||||
一个类或结构体可以根据自身需要提供多个下标实现,使用下标时将通过入参的数量和类型进行区分,自动匹配合适的下标,这就是*下标的重载*。
|
||||
|
||||
@ -140,3 +140,17 @@ func indexIsValid(row: Int, column: Int) -> Bool {
|
||||
let someValue = matrix[2, 2]
|
||||
// 断言将会触发,因为 [2, 2] 已经超过了 matrix 的范围
|
||||
```
|
||||
|
||||
## 类型下标{#type-subscripts}
|
||||
正如上节所述,实例下标是在特定类型的一个实例上调用的下标。你也可以定义一种在这个类型本身上调用的下标。这种下标的类型被称作类型下标。你可以通过在 `subscript` 关键字之前写下 `static` 关键字的方式来表示一个类型下标。类可以使用 `class` 关键字来允许子类重写父类中对那个下标的实现。下面的例子展示了如何定义和调用一个类型下标:
|
||||
```
|
||||
enum Planet: Int {
|
||||
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
|
||||
static subscript(n: Int) -> Planet {
|
||||
return Planet(rawValue: n)!
|
||||
}
|
||||
}
|
||||
let mars = Planet[4]
|
||||
print(mars)
|
||||
```
|
||||
|
||||
|
||||
@ -240,6 +240,20 @@ struct Size {
|
||||
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}
|
||||
|
||||
构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为*构造器代理*,它能避免多个构造器间的代码重复。
|
||||
@ -521,7 +535,7 @@ print("Bicycle: \(bicycle.description)")
|
||||
// 打印“Bicycle: 2 wheel(s)”
|
||||
```
|
||||
|
||||
如果父类的构造器没有在阶段 2 过程中做自定义操作,并且父类有一个无参数的自定义构造器。你可以在所有父类的存储属性赋值之后省略 `super.init()` 的调用。
|
||||
如果子类的构造器没有在阶段 2 过程中做自定义操作,并且父类有一个无参数的指定构造器,你可以在所有子类的存储属性赋值之后省略 `super.init()` 的调用。
|
||||
|
||||
这个例子定义了另一个 `Vehicle` 的子类 `Hoverboard` ,只设置它的 `color` 属性。这个构造器依赖隐式调用父类的构造器来完成,而不是显示调用 `super.init()`。
|
||||
|
||||
|
||||
@ -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 函数,并且通过传递到它的调用者来处理这些错误。
|
||||
|
||||
|
||||
@ -242,7 +242,7 @@ class SomeSubClass: SomeSuperClass, SomeProtocol {
|
||||
|
||||
## 协议作为类型 {#protocols-as-types}
|
||||
|
||||
尽管协议本身并未实现任何功能,但是协议可以被当做一个功能完备的类型来使用。
|
||||
尽管协议本身并未实现任何功能,但是协议可以被当做一个功能完备的类型来使用。协议作为类型使用,有时被称作「存在类型」,这个名词来自「存在着一个类型 T,该类型遵循协议 T」。
|
||||
|
||||
协议可以像其他普通类型一样使用,使用场景如下:
|
||||
|
||||
@ -272,7 +272,7 @@ class Dice {
|
||||
|
||||
例子中定义了一个 `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`。
|
||||
|
||||
@ -772,7 +772,7 @@ class Counter {
|
||||
|
||||
这里使用了两层可选链式调用。首先,由于 `dataSource` 可能为 `nil`,因此在 `dataSource` 后边加上了 `?`,以此表明只在 `dataSource` 非空时才去调用 `increment(forCount:)` 方法。其次,即使 `dataSource` 存在,也无法保证其是否实现了 `increment(forCount:)` 方法,因为这个方法是可选的。因此,`increment(forCount:)` 方法同样使用可选链式调用进行调用,只有在该方法被实现的情况下才能调用它,所以在 `increment(forCount:)` 方法后边也加上了 `?`。
|
||||
|
||||
调用 `increment(forCount:)` 方法在上述两种情形下都有可能失败,所以返回值为 `Int?` 类型。虽然在 `CounterDataSource` 协议中,`increment(forCount:)` 的返回值类型是非可选 `Int`。另外,即使这里使用了两层可选链式调用,最后的返回结果依旧是单层的可选类型。关于这一点的更多信息,请查阅 [连接多层可选链式调用](./16_Optional_Chaining)
|
||||
调用 `increment(forCount:)` 方法在上述两种情形下都有可能失败,所以返回值为 `Int?` 类型。虽然在 `CounterDataSource` 协议中,`increment(forCount:)` 的返回值类型是非可选 `Int`。另外,即使这里使用了两层可选链式调用,最后的返回结果依旧是单层的可选类型。关于这一点的更多信息,请查阅 [连接多层可选链式调用](./16_Optional_Chaining)。
|
||||
|
||||
在调用 `increment(forCount:)` 方法后,`Int?` 型的返回值通过可选绑定解包并赋值给常量 `amount`。如果可选值确实包含一个数值,也就是说,数据源和方法都存在,数据源方法返回了一个有效值。之后便将解包后的 `amount` 加到 `count` 上,增量操作完成。
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# 泛型
|
||||
|
||||
*泛型代码*让你能根据自定义的需求,编写出适用于任意类型的、灵活可复用的函数及类型。你可避免编写重复的代码,用一种清晰抽象的方式来表达代码的意图。
|
||||
*泛型代码*让你能根据自定义的需求,编写出适用于任意类型的、灵活可复用的函数及类型。你可避免编写重复的代码,而是用一种清晰抽象的方式来表达代码的意图。
|
||||
|
||||
泛型是 Swift 最强大的特性之一,很多 Swift 标准库是基于泛型代码构建的。实际上,即使你没有意识到,你也一直在*语言指南*中使用泛型。例如,Swift 的 `Array` 和 `Dictionary` 都是泛型集合。你可以创建一个 `Int` 类型数组,也可创建一个 `String` 类型数组,甚至可以是任意其他 Swift 类型的数组。同样,你也可以创建一个存储任意指定类型的字典,并对该类型没有限制。
|
||||
|
||||
@ -226,6 +226,8 @@ if let topItem = stackOfStrings.topItem {
|
||||
// 打印“The top item on the stack is tres.”
|
||||
```
|
||||
|
||||
泛型类型的扩展,还可以包括类型扩展需要额外满足的条件,从而对类型添加新功能,这一部分将在[具有泛型 Where 子句的扩展](#extensions-with-a-generic-where-clause)中进行讨论。
|
||||
|
||||
## 类型约束 {#type-constraints}
|
||||
|
||||
`swapTwoValues(_:_:)` 函数和 `Stack` 适用于任意类型。不过,如果能对泛型函数或泛型类型中添加特定的*类型约束*,这将在某些情况下非常有用。类型约束指定类型参数必须继承自指定类、遵循特定的协议或协议组合。
|
||||
@ -408,7 +410,7 @@ struct Stack<Element>: Container {
|
||||
|
||||
### 扩展现有类型来指定关联类型 {#extending-an-existing-type-to-specify-an-associated-type}
|
||||
|
||||
[在扩展添加协议一致性](./21_Protocols.md#adding_protocol_conformance_with_an_extension)中描述了如何利用扩展让一个已存在的类型符合一个协议,这包括使用了关联类型协议。
|
||||
[在扩展添加协议一致性](./21_Protocols.md#adding_protocol_conformance_with_an_extension) 中描述了如何利用扩展让一个已存在的类型遵循一个协议,这包括使用了关联类型协议。
|
||||
|
||||
Swift 的 `Array` 类型已经提供 `append(_:)` 方法,`count` 属性,以及带有 `Int` 索引的下标来检索其元素。这三个功能都符合 `Container` 协议的要求,也就意味着你只需声明 `Array` 遵循`Container` 协议,就可以扩展 Array,使其遵从 Container 协议。你可以通过一个空扩展来实现这点,正如通过扩展采纳协议中的描述:
|
||||
|
||||
@ -433,7 +435,7 @@ protocol Container {
|
||||
|
||||
要遵守 `Container` 协议,`Item` 类型也必须遵守 `Equatable` 协议。
|
||||
|
||||
### 在关联类型约束里使用协议 {#using-a-protocol-in-its-associated-type’s-constraints}
|
||||
### 在关联类型约束里使用协议 {#using-a-protocol-in-its-associated-types-constraints}
|
||||
|
||||
协议可以作为它自身的要求出现。例如,有一个协议细化了 `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
|
||||
extension Stack: SuffixableContainer {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
Swift 使用*自动引用计数(ARC)*机制来跟踪和管理你的应用程序的内存。通常情况下,Swift 内存管理机制会一直起作用,你无须自己来考虑内存的管理。ARC 会在类的实例不再被使用时,自动释放其占用的内存。
|
||||
|
||||
然而在少数情况下,为了能帮助你管理内存,ARC 需要更多的,代码之间关系的信息。本章描述了这些情况,并且为你示范怎样才能使 ARC 来管理你的应用程序的所有内存。在 Swift 使用 ARC 与在 Obejctive-C 中使用 ARC 非常类似,具体请参考[过渡到 ARC 的发布说明](https://developer.apple.com/library/content/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226)
|
||||
然而在少数情况下,为了能帮助你管理内存,ARC 需要更多的,代码之间关系的信息。本章描述了这些情况,并且为你示范怎样才能使 ARC 来管理你的应用程序的所有内存。在 Swift 使用 ARC 与在 Obejctive-C 中使用 ARC 非常类似,具体请参考 [过渡到 ARC 的发布说明](https://developer.apple.com/library/content/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226)。
|
||||
|
||||
> 注意
|
||||
>
|
||||
|
||||
@ -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
|
||||
public class A {
|
||||
@ -200,7 +200,7 @@ internal class B: A {
|
||||
}
|
||||
```
|
||||
|
||||
我们甚至可以在子类中,用子类成员去访问访问级别更低的父类成员,只要这一操作在相应访问级别的限制范围内(也就是说,在同一源文件中访问父类 `private` 级别的成员,在同一模块内访问父类 `internal` 级别的成员):
|
||||
我们甚至可以在子类中,用子类成员去访问访问级别更低的父类成员,只要这一操作在相应访问级别的限制范围内(也就是说,在同一源文件中访问父类 `fileprivate` 级别的成员,在同一模块内访问父类 `internal` 级别的成员):
|
||||
|
||||
```swift
|
||||
public class A {
|
||||
|
||||
249
source/chapter2/27_Opaque_Types.md
Normal file
249
source/chapter2/27_Opaque_Types.md
Normal 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`。
|
||||
@ -162,9 +162,9 @@ Swift 的*“词法结构(lexical structure)”* 描述了能构成该语言
|
||||
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` 的类型注解。
|
||||
|
||||
> 字面量语法
|
||||
>
|
||||
|
||||
@ -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
|
||||
@ -56,10 +57,9 @@ func someFunction(a: Int) { /* ... */ }
|
||||
|
||||
#### type-annotation {#type-annotation}
|
||||
> *类型注解* → **:** [*特性列表*](./07_Attributes.md#attributes)<sub>可选</sub> **输入输出参数**<sub>可选</sub> [*类型*](#type)
|
||||
>
|
||||
|
||||
## 类型标识符 {#type-identifier}
|
||||
类型标识符引用命名型类型,还可引用命名型或复合型类型的别名。
|
||||
## 类型标识符 {#type-identifier-h}
|
||||
*类型标识符*引用命名型类型,还可引用命名型或复合型类型的别名。
|
||||
|
||||
大多数情况下,类型标识符引用的是与之同名的命名型类型。例如类型标识符 `Int` 引用命名型类型 `Int`,同样,类型标识符 `Dictionary<String, Int>` 引用命名型类型 `Dictionary<String, Int>`。
|
||||
|
||||
@ -85,10 +85,9 @@ var someValue: ExampleModule.MyType
|
||||
|
||||
#### type-name {#type-name}
|
||||
> *类型名称* → [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
|
||||
## 元组类型 {#tuple-type}
|
||||
元组类型是使用括号括起来的零个或多个类型,类型间用逗号隔开。
|
||||
## 元组类型 {#tuple-type-h}
|
||||
*元组类型*是使用括号括起来的零个或多个类型,类型间用逗号隔开。
|
||||
|
||||
你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符紧跟一个冒号 `(:)` 组成。[函数和多返回值](../chapter2/06_Functions.md#functions_with_multiple_return_values) 章节里有一个展示上述特性的例子。
|
||||
|
||||
@ -122,8 +121,8 @@ someTuple = (left: 5, right: 5) // 错误:命名类型不匹配
|
||||
> *元素名* → [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
|
||||
## 函数类型 {#function-type}
|
||||
函数类型表示一个函数、方法或闭包的类型,它由参数类型和返回值类型组成,中间用箭头(`->`)隔开:
|
||||
## 函数类型 {#function-type-h}
|
||||
*函数类型*表示一个函数、方法或闭包的类型,它由参数类型和返回值类型组成,中间用箭头(`->`)隔开:
|
||||
|
||||
> (`参数类型`)->(`返回值类型`)
|
||||
|
||||
@ -219,7 +218,7 @@ func takesTwoFunctions(first: (Any) -> Void, second: (Any) -> Void) {
|
||||
> *参数标签* → [*标识符*](./02_Lexical_Structure.md#identifier)
|
||||
>
|
||||
|
||||
## 数组类型 {#array-type}
|
||||
## 数组类型 {#array-type-h}
|
||||
Swift 语言为标准库中定义的 `Array<Element>` 类型提供了如下语法糖:
|
||||
|
||||
> [`类型`]
|
||||
@ -251,7 +250,7 @@ var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
||||
> *数组类型* → **[** [*类型*](#type) **]**
|
||||
>
|
||||
|
||||
## 字典类型 {#dictionary-type}
|
||||
## 字典类型 {#dictionary-type-h}
|
||||
Swift 语言为标准库中定义的 `Dictionary<Key, Value>` 类型提供了如下语法糖:
|
||||
|
||||
> [`键类型` : `值类型`]
|
||||
@ -279,7 +278,7 @@ let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]
|
||||
> *字典类型* → **[** [*类型*](#type) **:** [*类型*](#type) **]**
|
||||
>
|
||||
|
||||
## 可选类型 {#optional-type}
|
||||
## 可选类型 {#optional-type-h}
|
||||
Swift 定义后缀 `?` 来作为标准库中定义的命名型类型 `Optional<Wrapped>` 的语法糖。换句话说,下面两个声明是等价的:
|
||||
|
||||
```swift
|
||||
@ -311,7 +310,7 @@ optionalInteger! // 42
|
||||
> *可选类型* → [*类型*](#type) **?**
|
||||
>
|
||||
|
||||
## 隐式解析可选类型 {#implicitly-unwrapped-optional-type}
|
||||
## 隐式解析可选类型 {#implicitly-unwrapped-optional-type-h}
|
||||
当可以被访问时,Swift 语言定义后缀 `!` 作为标准库中命名类型 `Optional<Wrapped>` 的语法糖,来实现自动解包的功能。如果尝试对一个值为 `nil` 的可选类型进行隐式解包,将会产生运行时错误。因为隐式解包,下面两个声明等价:
|
||||
|
||||
```swift
|
||||
@ -346,13 +345,12 @@ let implicitlyUnwrappedArray: [Int]! // 正确
|
||||
> *隐式解析可选类型* → [*类型*](#type) **!**
|
||||
>
|
||||
|
||||
## 协议合成类型 {#protocol-composition-type}
|
||||
协议合成类型定义了一种遵循协议列表中每个指定协议的类型,或者一个现有类型的子类并遵循协议列表中每个指定协议。协议合成类型只能用在类型注解、泛型参数子句和泛型 `where` 子句中指定类型。
|
||||
## 协议合成类型 {#protocol-composition-type-h}
|
||||
*协议合成类型*定义了一种遵循协议列表中每个指定协议的类型,或者一个现有类型的子类并遵循协议列表中每个指定协议。协议合成类型只能用在类型注解、泛型参数子句和泛型 `where` 子句中指定类型。
|
||||
|
||||
协议合成类型的形式如下:
|
||||
|
||||
> `Protocol 1` & `Procotol 2`
|
||||
>
|
||||
|
||||
协议合成类型允许你指定一个值,其类型遵循多个协议的要求而不需要定义一个新的命名型协议来继承它想要符合的各个协议。比如,协议合成类型 `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-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`。
|
||||
|
||||
@ -428,10 +450,48 @@ let anotherInstance = metatype.init(string: "some string")
|
||||
|
||||
#### metatype-type {#metatype-type}
|
||||
> *元类型* → [*类型*](#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)。
|
||||
|
||||
@ -450,11 +510,9 @@ let anotherInstance = metatype.init(string: "some string")
|
||||
> *类型继承列表* → [*类型标识符*](#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`)。
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ try 表达式由 `try` 运算符加上紧随其后的可抛出错误的表达式
|
||||
|
||||
如果可抛出错误的表达式抛出了错误,将会引发运行时错误。
|
||||
|
||||
在二进制运算符左侧的表达式被标记上 `try`、`try?` 或者 `try!` 时,这个运算符对整个二进制表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。
|
||||
在二元运算符左侧的表达式被标记上 `try`、`try?` 或者 `try!` 时,这个运算符对整个二元表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。
|
||||
|
||||
```swift
|
||||
sum = try someThrowingFunction() + anotherThrowingFunction() // try 对两个函数调用都产生作用
|
||||
@ -65,7 +65,7 @@ sum = try (someThrowingFunction() + anotherThrowingFunction()) // try 对两个
|
||||
sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误:try 只对第一个函数调用产生作用
|
||||
```
|
||||
|
||||
`try` 表达式不能出现在二进制运算符的的右侧,除非二进制运算符是赋值运算符或者 `try` 表达式是被圆括号括起来的。
|
||||
`try` 表达式不能出现在二元运算符的的右侧,除非二元运算符是赋值运算符或者 `try` 表达式是被圆括号括起来的。
|
||||
|
||||
关于 `try`、`try?` 和 `try!` 的更多信息,以及该如何使用的例子,请参阅 [错误处理](../chapter2/17_Error_Handling.md)。
|
||||
> Try 表达式语法
|
||||
@ -275,7 +275,7 @@ var emptyDictionary: [String : Double] = [:]
|
||||
|
||||
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
|
||||
{ (parameters) -> return type in
|
||||
>
|
||||
statements
|
||||
}
|
||||
```
|
||||
@ -448,7 +447,6 @@ struct Point {
|
||||
```swift
|
||||
myFunction {
|
||||
(x: Int, y: Int) -> Int in
|
||||
>
|
||||
return x + y
|
||||
}
|
||||
|
||||
@ -466,7 +464,7 @@ myFunction { $0 + $1 }
|
||||
|
||||
使用闭包表达式时,可以不必将其存储在一个变量或常量中,例如作为函数调用的一部分来立即使用一个闭包。在上面的例子中,传入 `myFunction` 的闭包表达式就是这种立即使用类型的闭包。因此,一个闭包是否逃逸与其使用时的上下文相关。一个会被立即调用或者作为函数的非逃逸参数传递的闭包表达式是非逃逸的,否则,这个闭包表达式是逃逸的。
|
||||
|
||||
关于逃逸闭包的内容,请参阅[逃逸闭包](./chapter2/07_Closures.md#escaping_closures)
|
||||
关于逃逸闭包的内容,请参阅 [逃逸闭包](./chapter2/07_Closures.md#escaping_closures)。
|
||||
|
||||
## 捕获列表 {#capture-lists}
|
||||
默认情况下,闭包会捕获附近作用域中的常量和变量,并使用强引用指向它们。你可以通过一个*捕获列表*来显式指定它的捕获行为。
|
||||
@ -729,7 +727,6 @@ let myGreeting = greetings[keyPath: \[String].[1]]
|
||||
var index = 2
|
||||
let path = \[String].[index]
|
||||
let fn: ([String]) -> String = { strings in strings[index] }
|
||||
>
|
||||
|
||||
print(greetings[keyPath: path])
|
||||
// 打印 "bonjour"
|
||||
@ -775,7 +772,7 @@ print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth
|
||||
// 打印 "64"
|
||||
```
|
||||
|
||||
关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i) 和 [Key-Value 观察编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i)
|
||||
关于更多如何使用 key path 与 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 表达式语法
|
||||
>
|
||||
@ -840,7 +837,6 @@ extension SomeClass {
|
||||
func doSomething(_ x: String) { }
|
||||
}
|
||||
let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void)
|
||||
>
|
||||
```
|
||||
|
||||
由于选择器是在编译时创建的,因此编译器可以检查方法或者属性是否存在,以及是否在运行时暴露给了 Objective-C 。
|
||||
@ -903,7 +899,7 @@ print(keyPath == c.getSomeKeyPath())
|
||||
|
||||
由于 key-path 字符串表达式在编译期才创建,编译期可以检查属性是否存在,以及属性是否暴露给 Objective-C 运行时。
|
||||
|
||||
关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](./https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.md#//apple_ref/doc/uid/10000107i) 和 [Key-Value 观察编程](./https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.md#//apple_ref/doc/uid/10000177i)
|
||||
关于更多如何使用 key path 与 Objective-C APIs 交互的信息,请参阅 [在 Swift 中使用 Objective-C 运行时特性](./https://developer.apple.com/documentation/swift/using_objective_c_runtime_features_in_swift)。关于更多 key-value 编程和 key-value 观察的信息,请参阅 [Key-Value 编程](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.md#//apple_ref/doc/uid/10000107i) 和 [Key-Value 观察编程](./https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.md#//apple_ref/doc/uid/10000177i)。
|
||||
|
||||
> 注意
|
||||
>
|
||||
@ -1036,7 +1032,6 @@ class SomeSubClass: SomeSuperClass {
|
||||
```swift
|
||||
// 类型注解是必须的,因为 String 类型有多种构造器
|
||||
let initializer: Int -> String = String.init
|
||||
>
|
||||
let oneTwoThree = [1, 2, 3].map(initializer).reduce("", combine: +)
|
||||
print(oneTwoThree)
|
||||
// 打印“123”
|
||||
@ -1087,9 +1082,9 @@ t.0 = t.1
|
||||
|
||||
对于模块的成员来说,只能直接访问顶级声明中的成员。
|
||||
|
||||
使用 `dynamicMemberLookup` 属性声明的类型包含可以在运行时查找的成员,具体请参阅 [属性](./07_Attributes.md)
|
||||
使用 `dynamicMemberLookup` 属性声明的类型包含可以在运行时查找的成员,具体请参阅 [属性](./07_Attributes.md)。
|
||||
|
||||
为了区分只有参数名有所不同的方法或构造器,在圆括号中写出参数名,参数名后紧跟一个冒号,对于没有参数名的参数,使用下划线代替参数名。而对于重载方法,则需使用类型标注进行区分。例如:
|
||||
为了区分只有参数名有所不同的方法或构造器,在圆括号中写出参数名,参数名后紧跟一个冒号,对于没有参数名的参数,使用下划线代替参数名。而对于重载方法,则需使用类型注解进行区分。例如:
|
||||
|
||||
```swift
|
||||
class SomeClass {
|
||||
@ -1106,7 +1101,6 @@ let b = instance.someMethod(_:y:) // 无歧义
|
||||
let d = instance.overloadedMethod // 有歧义
|
||||
let d = 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]
|
||||
.sort()
|
||||
.filter { $0 > 5 }
|
||||
>
|
||||
.map { $0 * 100 }
|
||||
```
|
||||
|
||||
@ -1232,7 +1225,6 @@ if let unwrappedC = c {
|
||||
|
||||
```swift
|
||||
func someFunctionWithSideEffects() -> Int {
|
||||
>
|
||||
// 译者注:为了能看出此函数是否被执行,加上了一句打印
|
||||
print("someFunctionWithSideEffects")
|
||||
return 42
|
||||
|
||||
@ -135,9 +135,9 @@ print("The second number is \(secondNumber).")
|
||||
// 打印“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)。
|
||||
|
||||
@ -187,7 +187,7 @@ var 变量名称: 类型 = 表达式
|
||||
|
||||
可以在全局范围,函数内部,或者在类和结构体的声明中使用这种形式来声明一个变量。当变量以这种形式在全局范围或者函数内部被声明时,它代表一个存储型变量。当它在类或者结构体中被声明时,它代表一个*存储型变量属性(stored variable property)*。
|
||||
|
||||
用于初始化的表达式不可以在协议的声明中出现,在其他情况下,该表达式是可选的。如果没有初始化表达式,那么变量声明必须包含类型标注(`:` *type*)。
|
||||
用于初始化的表达式不可以在协议的声明中出现,在其他情况下,该表达式是可选的。如果没有初始化表达式,那么变量声明必须包含类型注解(`:` *type*)。
|
||||
|
||||
如同常量声明,如果变量名称是元组形式,元组中每一项的名称都会和初始化表达式中对应的值进行绑定。
|
||||
|
||||
@ -236,7 +236,7 @@ var 变量名称: 类型 = 表达式 {
|
||||
可以为任何存储型属性添加观察器。也可以通过重写父类属性的方式为任何继承的属性(无论是存储型还是计算型的)添加观察器
|
||||
,正如 [重写属性观察器](../chapter2/13_Inheritance.md#overriding_property_observers) 中所描述的。
|
||||
|
||||
用于初始化的表达式在类或者结构的声明中是可选的,但是在其他声明中则是必须的。如果可以从初始化表达式中推断出类型信息,那么可以不提供类型标注。
|
||||
用于初始化的表达式在类或者结构的声明中是可选的,但是在其他声明中则是必须的。如果可以从初始化表达式中推断出类型信息,那么可以不提供类型注解。
|
||||
|
||||
当变量或属性的值被改变时,`willSet` 和 `didSet` 观察器提供了一种观察方法。观察器会在变量的值被改变时调用,但不会在初始化时被调用。
|
||||
|
||||
@ -251,11 +251,6 @@ var 变量名称: 类型 = 表达式 {
|
||||
### 类型变量属性 {#type-variable-properties}
|
||||
要声明一个类型变量属性,用 `static` 声明修饰符标记该声明。类可以改用 `class` 声明修饰符标记类的类型计算型属性从而允许子类重写超类的实现。类型属性在 [类型属性](../chapter2/10_Properties.md#type_properties) 章节有详细讨论。
|
||||
|
||||
> 注意
|
||||
>
|
||||
> 在一个类声明中,使用关键字 `static` 与同时使用 `class` 和 `final` 去标记一个声明的效果相同。
|
||||
>
|
||||
|
||||
|
||||
#### grammer_of_a_variable_declaration {#grammer-of-a-variable-declaration}
|
||||
> 变量声明语法
|
||||
@ -264,15 +259,15 @@ var 变量名称: 类型 = 表达式 {
|
||||
#### variable-declaration {#variable-declaration}
|
||||
> *变量声明* → [*变量声明头*](#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) [*类型标注*](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
|
||||
typealias StringDictionary<Value> = Dictionary<String, Value>
|
||||
>
|
||||
|
||||
// 下列两个字典拥有同样的类型
|
||||
var dictionary1: StringDictionary<Int> = [:]
|
||||
>
|
||||
var dictionary2: Dictionary<String, Int> = [:]
|
||||
>
|
||||
```
|
||||
|
||||
当一个类型别名带着泛型参数一起被声明时,这些参数的约束必须与现有参数的约束完全匹配。例如:
|
||||
|
||||
```swift
|
||||
typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>
|
||||
>
|
||||
```
|
||||
|
||||
因为类型别名可以和现有类型相互交换使用,类型别名不可以引入额外的类型约束。
|
||||
@ -389,7 +380,6 @@ protocol Sequence {
|
||||
}
|
||||
|
||||
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
|
||||
func 函数名称(参数列表) -> 返回类型 {
|
||||
>
|
||||
语句
|
||||
}
|
||||
```
|
||||
@ -439,6 +428,8 @@ func 函数名称(参数列表) {
|
||||
|
||||
每个参数的类型都要标明,因为它们不能被推断出来。如果您在某个参数类型前面加上了 `inout`,那么这个参数就可以在这个函数作用域当中被修改。更多关于 `inout` 参数的讨论,请参阅 [输入输出参数](#in-out_parameters)。
|
||||
|
||||
函数声明中语句只包含一个表达式,可以理解为返回该表达式的值。
|
||||
|
||||
函数可以使用元组类型作为返回类型来返回多个值。
|
||||
|
||||
函数定义可以出现在另一个函数声明内。这种函数被称作*嵌套函数(nested function)*。
|
||||
@ -456,7 +447,6 @@ func 函数名称(参数列表) {
|
||||
|
||||
```swift
|
||||
func f(x: Int, y: Int) -> Int { return x + y }
|
||||
>
|
||||
f(x: 1, y: 2) // 参数 x 和 y 都有标签
|
||||
```
|
||||
|
||||
@ -495,7 +485,6 @@ repeatGreeting("Hello, world!", count: 2) // count 有标签, greeting 没有
|
||||
|
||||
```swift
|
||||
func someFunction(a: inout Int) -> () -> Int {
|
||||
>
|
||||
return { [a] in return a + 1 }
|
||||
}
|
||||
```
|
||||
@ -535,7 +524,7 @@ _ : 参数类型
|
||||
|
||||
```swift
|
||||
func f(x: Int = 42) -> Int { return x }
|
||||
>
|
||||
|
||||
f() // 有效,使用默认值
|
||||
f(7) // 有效,提供了值
|
||||
f(x: 7) // 无效,该参数没有外部名称
|
||||
@ -546,14 +535,13 @@ f(x: 7) // 无效,该参数没有外部名称
|
||||
|
||||
子类重写超类中的方法必须以 `override` 声明修饰符标记。重写方法时不使用 `override` 修饰符,或者被 `override` 修饰符修饰的方法并未对超类方法构成重写,都会导致编译错误。
|
||||
|
||||
枚举或者结构体中的类型方法,要以 `static` 声明修饰符标记,而对于类中的类型方法,除了使用 `static`,还可使用 `class` 声明修饰符标记。类中使用 `class` 声明修饰的方法可以被子类实现重写;类中使用 `static` 声明修饰的方法不可被重写。
|
||||
枚举或者结构体中的类型方法,要以 `static` 声明修饰符标记,而对于类中的类型方法,除了使用 `static`,还可使用 `class` 声明修饰符标记。类中使用 `class` 声明修饰的方法可以被子类实现重写;类中使用 `class final` 或 `static` 声明修饰的方法不可被重写。
|
||||
|
||||
### 抛出错误的函数和方法 {#throwing-functions-and-methods}
|
||||
可以抛出错误的函数或方法必须使用 `throws` 关键字标记。这类函数和方法被称为抛出函数和抛出方法。它们有着下面的形式:
|
||||
|
||||
```swift
|
||||
func 函数名称(参数列表) throws -> 返回类型 {
|
||||
>
|
||||
语句
|
||||
}
|
||||
```
|
||||
@ -571,7 +559,6 @@ func 函数名称(参数列表) throws -> 返回类型 {
|
||||
|
||||
```swift
|
||||
func someFunction(callback: () throws -> Void) rethrows {
|
||||
>
|
||||
try callback()
|
||||
}
|
||||
```
|
||||
@ -583,7 +570,6 @@ func alwaysThrows() throws {
|
||||
throw SomeError.error
|
||||
}
|
||||
func someFunction(callback: () throws -> Void) rethrows {
|
||||
>
|
||||
do {
|
||||
try callback()
|
||||
try alwaysThrows() // 非法, alwaysThrows() 不是一个抛出函数类型的参数
|
||||
@ -653,11 +639,11 @@ Swift 定义了 `Never` 类型,它表示函数或者方法不会返回给它
|
||||
>
|
||||
#### 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}
|
||||
@ -711,7 +697,6 @@ enum Number {
|
||||
}
|
||||
|
||||
// f 的类型为 (Int) -> Number
|
||||
>
|
||||
let f = Number.integer
|
||||
|
||||
// 利用 f 把一个整数数组转成 Number 数组
|
||||
@ -727,7 +712,6 @@ let evenInts: [Number] = [0, 2, 4, 6].map(f)
|
||||
|
||||
```swift
|
||||
enum Tree<T> {
|
||||
>
|
||||
case empty
|
||||
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` 关键在写在冒号后面的继承的协议列表的首位。例如,下面的协议只能被类类型采纳:
|
||||
|
||||
@ -1092,7 +1076,9 @@ var 属性名: 类型 { get set }
|
||||
|
||||
同其它协议成员声明一样,这些属性声明仅仅针对符合该协议的类型声明了 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)。
|
||||
|
||||
@ -1103,13 +1089,13 @@ var 属性名: 类型 { get set }
|
||||
>
|
||||
#### 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}
|
||||
协议可以通过在协议声明主体中引入一个协议方法声明,来声明符合的类型必须实现的方法。协议方法声明和函数方法声明有着相同的形式,但有两项例外:它们不包括函数体,也不能包含默认参数。关于如何实现协议中的方法要求的例子,请参阅 [方法要求](../chapter2/21_Protocols.md#method_requirements)。
|
||||
|
||||
使用 `static` 声明修饰符可以在协议声明中声明一个类型方法。类在实现这些方法时使用 `class` 声明修饰符。结构体实现这些方法时必须使用 `static` 声明修饰符。通过扩展实现时亦是如此(类的扩展中使用 `class` 声明修饰符,结构体的扩展中使用 `static` 声明修饰符)。
|
||||
协议声明中声明一个类型方法,方法声明语句必须用 `static` 声明修饰符。结构体和枚举遵循协议时,必须使用 `static` 关键字修饰,而类遵循协议时,使用 `static` 或 `class` 关键字皆可。当结构体,枚举或类添加扩展遵循协议时,和之前扩展用到的关键字保持一致。扩展为类方法提供默认实现时,必须使用 `static` 关键字修饰。
|
||||
|
||||
另请参阅 [函数声明](#function_declaration)。
|
||||
|
||||
@ -1150,11 +1136,12 @@ var 属性名: 类型 { get set }
|
||||
|
||||
```swift
|
||||
subscript (参数列表) -> 返回类型 { get set }
|
||||
>
|
||||
```
|
||||
|
||||
下标声明只为符合类型声明了 getter 和 setter 要求。如果下标声明包含 `get` 和 `set` 关键字,符合类型也必须实现 getter 和 setter 子句。如果下标声明只包含 `get` 关键字,符合类型必须实现 getter 子句,可以选择是否实现 setter 子句。
|
||||
|
||||
协议声明中声明一个静态下标,下标声明语句必须用 `static` 声明修饰符。当结构体和枚举遵循该协议时,下标声明使用 `static` 关键字修饰,而类遵循该协议时,使用 `static` 或 `class` 关键字皆可。当结构体,枚举或类添加扩展遵循协议时,和之前扩展用到的关键字保持一致。扩展为下标声明提供默认实现时,必须使用 `static` 关键字修饰。
|
||||
|
||||
另请参阅 [下标声明](#subscript_declaration)。
|
||||
|
||||
|
||||
@ -1441,18 +1428,15 @@ doSomething(with: oneAndTwo)
|
||||
```swift
|
||||
protocol Serializable {
|
||||
func serialize() -> Any
|
||||
>
|
||||
}
|
||||
|
||||
extension Array: Serializable where Element == Int {
|
||||
func serialize() -> Any {
|
||||
>
|
||||
// implementation
|
||||
}
|
||||
}
|
||||
extension Array: Serializable where Element == String {
|
||||
func serialize() -> Any {
|
||||
>
|
||||
// implementation
|
||||
}
|
||||
}
|
||||
@ -1468,7 +1452,6 @@ extension String: SerializableInArray { }
|
||||
|
||||
extension Array: Serializable where Element: SerializableInArray {
|
||||
func serialize() -> Any {
|
||||
>
|
||||
// 具体实现
|
||||
}
|
||||
}
|
||||
@ -1536,7 +1519,6 @@ extension Array: Loggable where Element: MarkedLoggable { }
|
||||
|
||||
```swift
|
||||
subscript (参数列表) -> 返回类型 {
|
||||
>
|
||||
get {
|
||||
语句
|
||||
}
|
||||
@ -1548,20 +1530,25 @@ subscript (参数列表) -> 返回类型 {
|
||||
|
||||
下标声明只能出现在类、结构体、枚举、扩展和协议的声明中。
|
||||
|
||||
参数列表指定一个或多个用于在相关类型的下标表达式中访问元素的索引(例如,表达式 `object[i]` 中的 `i`)。索引可以是任意类型,但是必须包含类型标注。返回类型指定了被访问的元素的类型。
|
||||
参数列表指定一个或多个用于在相关类型的下标表达式中访问元素的索引(例如,表达式 `object[i]` 中的 `i`)。索引可以是任意类型,但是必须包含类型注解。返回类型指定了被访问的元素的类型。
|
||||
|
||||
和计算型属性一样,下标声明支持对元素的读写操作。getter 用于读取值,setter 用于写入值。setter 子句是可选的,当仅需要一个 getter 子句时,可以将二者都忽略,直接返回请求的值即可。但是,如果提供了 setter 子句,就必须提供 getter 子句。
|
||||
|
||||
圆括号以及其中的 setter 名称是可选的。如果提供了 setter 名称,它会作为 setter 的参数名称。如果不提供 setter 名称,那么 setter 的参数名称默认是 `value`。setter 名称的类型必须与返回类型相同。
|
||||
圆括号以及其中的 setter 名称是可选的。如果提供了 setter 名称,它会作为 setter 的参数名称。如果不提供 setter 名称,那么 setter 的参数名称默认是 `value`。setter 的参数类型必须与返回类型相同。
|
||||
|
||||
可以重写下标,只要参数列表或返回类型不同即可。还可以重写继承自超类的下标,此时必须使用 `override` 声明修饰符声明被重写的下标。
|
||||
|
||||
在默认情况下,下标中的参数不会含有
|
||||
下标参数遵循与函数参数相同的规则,但有两个例外。默认情况下,下标中使用的参数不需要指定标签,这与函数,方法和构造器不同。但是你也可以同它们一样,显式地提供参数标签。此外,下标不能有 `In-out` 参数。
|
||||
|
||||
同样可以在协议声明中声明下标,正如 [协议下标声明](#protocol_subscript_declaration) 中所述。
|
||||
|
||||
更多关于下标的信息和例子,请参阅 [下标](../chapter2/12_Subscripts.md)。
|
||||
|
||||
### 类型下标声明
|
||||
|
||||
声明一个由类型而不是类型实例公开的下标,请使用 `static` 声明修饰符标记下标声明。类可以使用 `class` 声明修饰符标记类型计算属性,以允许子类重写父类的实现。在类声明中,`static` 关键字具有与用 `class` 和 `final` 声明修饰符标记声明相同的效果。
|
||||
|
||||
|
||||
|
||||
#### grammer_of_a_subscript_declaration {#grammer-of-a-subscript-declaration}
|
||||
> 下标声明语法
|
||||
@ -1731,6 +1718,10 @@ Swift 定义了大量的优先级组来与标准库的运算符配合使用,
|
||||
## 声明修饰符 {#Declaration-Modifiers}
|
||||
声明修饰符都是关键字或上下文相关的关键字,可以修改一个声明的行为或者含义。可以在声明的特性(如果存在)和引入该声明的关键字之间,利用声明修饰符的关键字或上下文相关的关键字指定一个声明修饰符。
|
||||
|
||||
`class`
|
||||
|
||||
该修饰符用于修饰任何类成员,表明是类自身的成员,而不是类实例的成员。父类中使用该修饰符标记或者未被 `final` 修饰符标记的成员,都允许被子类重写。
|
||||
|
||||
`dynamic`
|
||||
|
||||
该修饰符用于修饰任何兼容 Objective-C 的类的成员。访问被 `dynamic` 修饰符标记的类成员将总是由 Objective-C 运行时系统进行动态派发,而不会由编译器进行内联或消虚拟化。
|
||||
@ -1755,6 +1746,10 @@ Swift 定义了大量的优先级组来与标准库的运算符配合使用,
|
||||
|
||||
该修饰符用于修饰类的指定构造器或便利构造器,表示该类所有的子类都必须实现该构造器。在子类实现该构造器时,必须同样使用 `required` 修饰符修饰该构造器。
|
||||
|
||||
`static`
|
||||
|
||||
该修饰符用于修饰结构体、类、枚举或协议的成员,表明是类型成员,而不是类型实例的成员。在类声明的作用范围内,使用 `static` 修饰符标记成员声明语句,同 `class` 和 `final` 修饰符具有相同的效果。但是类的常量类型属性是一个例外: `static` 没有问题,但是你无法为常量声明使用 `class` 或 `final` 修饰符。
|
||||
|
||||
`unowned`
|
||||
|
||||
该修饰符用于修饰存储型变量、常量或者存储型变量属性,表示该变量或属性持有其存储对象的无主引用。如果在此存储对象释放后尝试访问该对象,会引发运行时错误。如同弱引用一样,该引用类型的变量或属性必须是类类型。与弱引用不同的是,这种类型的变量或属性是非可选的。关于 `unowned` 更多的信息和例子,请参阅 [无主引用](../chapter2/23_Automatic_Reference_Counting.md#unowned_references)
|
||||
@ -1765,7 +1760,7 @@ Swift 定义了大量的优先级组来与标准库的运算符配合使用,
|
||||
|
||||
`unowned(unsafe)`
|
||||
|
||||
该修饰符用于修饰存储型变量、常量或者存储型变量属性,表示该变量或属性持有其存储对象的无主引用。如果在此存储对象释放后尝试访问该对象,会直接访问该对象释放前存储的内存地址,因此这是非内存安全的操作。如同弱引用一样,该引用类型的变量或属性必须是类类型。与弱引用不同的是,这种类型的变量或属性是非可选的。关于 `unowned` 更多的信息和例子,请参阅 [无主引用](
|
||||
该修饰符用于修饰存储型变量、常量或者存储型变量属性,表示该变量或属性持有其存储对象的无主引用。如果在此存储对象释放后尝试访问该对象,会直接访问该对象释放前存储的内存地址,因此这是非内存安全的操作。如同弱引用一样,该引用类型的变量或属性必须是类类型。与弱引用不同的是,这种类型的变量或属性是非可选的。关于 `unowned` 更多的信息和例子,请参阅 [无主引用](../chapter2/23_Automatic_Reference_Counting.md#resolving_strong_reference_cycles_between_class_instances)。
|
||||
|
||||
`weak`
|
||||
|
||||
|
||||
@ -151,7 +151,6 @@ dial.dynamicallyCall(withArguments: [4, 1, 1])
|
||||
@dynamicCallable
|
||||
struct Repeater {
|
||||
func dynamicallyCall(withKeywordArguments pairs: KeyValuePairs<String, Int>) -> String {
|
||||
>
|
||||
return pairs
|
||||
.map { label, count in
|
||||
repeatElement(label, count: count).joined(separator: " ")
|
||||
@ -183,7 +182,11 @@ repeatLabels(a: "four") // Error
|
||||
|
||||
该特性用于类、结构体、枚举或协议,让其能在运行时查找成员。该类型必须实现 `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
|
||||
@dynamicMemberLookup
|
||||
@ -191,7 +194,6 @@ struct DynamicStruct {
|
||||
let dictionary = ["someDynamicMember": 325,
|
||||
"someOtherMember": 787]
|
||||
subscript(dynamicMember member: String) -> Int {
|
||||
>
|
||||
return dictionary[member] ?? 1054
|
||||
}
|
||||
}
|
||||
@ -208,6 +210,24 @@ print(dynamic == equivalent)
|
||||
// 打印“true”
|
||||
```
|
||||
|
||||
根据键路径来动态地查找成员,可用于创建一个包裹数据的包装类型,该类型在编译时期进行类型检查。例如:
|
||||
|
||||
```swift
|
||||
struct Point { var x, y: Int }
|
||||
|
||||
@dynamicMemberLookup
|
||||
struct PassthroughWrapper<Value> {
|
||||
var value: Value
|
||||
subscript<T>(dynamicMember member: KeyPath<Value, T>) -> T {
|
||||
get { return value[keyPath: member] }
|
||||
}
|
||||
}
|
||||
|
||||
let point = Point(x: 381, y: 431)
|
||||
let wrapper = PassthroughWrapper(value: point)
|
||||
print(wrapper.x)
|
||||
```
|
||||
|
||||
### `GKInspectable` {#gkinspectable}
|
||||
|
||||
应用此属性,暴露一个自定义 GameplayKit 组件属性给 SpriteKit 编辑器 UI。
|
||||
@ -263,7 +283,7 @@ NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
|
||||
|
||||
- 父类有 `objc` 特性,且重写为子类的声明。
|
||||
- 遵循带有 `objc` 特性协议的声明。
|
||||
- 带有 `IBAction`、`IBOutlet`、`IBDesignable`、`IBInspectable`、`NSManaged` 或 `GKInspectable` 特性的声明。
|
||||
- 带有 `IBAction`、 `IBSegueAction` 、 `IBOutlet` 、 `IBDesignable` 、 `IBInspectable` 、 `NSManaged` 或 `GKInspectable` 特性的声明。
|
||||
|
||||
如果你将 `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` 特性是 `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` 用于修饰类的声明。
|
||||
|
||||
应用 `IBAction`、`IBOutlet`、`IBDesignable` 或者 `IBInspectable` 特性都意味着同时应用 `objc` 特性。
|
||||
应用 `IBAction`、`IBSegueAction`、`IBOutlet`、`IBDesignable` 或者 `IBInspectable` 特性都意味着同时应用 `objc` 特性。
|
||||
|
||||
## 类型特性 {#type-attributes}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
Swift 中的模式分为两类:一种能成功匹配任何类型的值,另一种在运行时匹配某个特定值时可能会失败。
|
||||
|
||||
第一类模式用于解构简单变量、常量和可选绑定中的值。此类模式包括通配符模式、标识符模式,以及包含前两种模式的值绑定模式和元组模式。你可以为这类模式指定一个类型标注,从而限制它们只能匹配某种特定类型的值。
|
||||
第一类模式用于解构简单变量、常量和可选绑定中的值。此类模式包括通配符模式、标识符模式,以及包含前两种模式的值绑定模式和元组模式。你可以为这类模式指定一个类型注解,从而限制它们只能匹配某种特定类型的值。
|
||||
|
||||
第二类模式用于全模式匹配,这种情况下你试图匹配的值在运行时可能不存在。此类模式包括枚举用例模式、可选模式、表达式模式和类型转换模式。你在 `switch` 语句的 `case` 标签中,`do` 语句的 `catch` 子句中,或者在 `if`、`while`、`guard` 和 `for-in` 语句的 `case` 条件句中使用这类模式。
|
||||
|
||||
@ -12,13 +12,13 @@ Swift 中的模式分为两类:一种能成功匹配任何类型的值,另
|
||||
>
|
||||
|
||||
#### pattern {#pattern}
|
||||
> *模式* → [*通配符模式*](#wildcard_pattern) [*类型标注*](03_Types.md#type-annotation)<sub>可选</sub>
|
||||
> *模式* → [*通配符模式*](#wildcard_pattern) [*类型注解*](03_Types.md#type-annotation)<sub>可选</sub>
|
||||
>
|
||||
> *模式* → [*标识符模式*](#identifier_pattern) [*类型标注*](03_Types.md#type-annotation)<sub>可选</sub>
|
||||
> *模式* → [*标识符模式*](#identifier_pattern) [*类型注解*](03_Types.md#type-annotation)<sub>可选</sub>
|
||||
>
|
||||
> *模式* → [*值绑定模式*](#value-binding-pattern)
|
||||
>
|
||||
> *模式* → [*元组模式*](#tuple-pattern) [*类型标注*](03_Types.md#type-annotation)<sub>可选</sub>
|
||||
> *模式* → [*元组模式*](#tuple-pattern) [*类型注解*](03_Types.md#type-annotation)<sub>可选</sub>
|
||||
>
|
||||
> *模式* → [*枚举用例模式*](#enum-case-pattern)
|
||||
>
|
||||
@ -91,7 +91,7 @@ case let (x, y):
|
||||
## 元组模式 {#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` 是一个表达式模式:
|
||||
|
||||
@ -228,7 +228,6 @@ default:
|
||||
```swift
|
||||
// 重载 ~= 运算符对字符串和整数进行比较
|
||||
func ~=(pattern: String, value: Int) -> Bool {
|
||||
>
|
||||
return pattern == "\(value)"
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
|
||||
```swift
|
||||
func simpleMax<T: Comparable>(_ x: T, _ y: T) -> T {
|
||||
>
|
||||
if x < 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
|
||||
let arrayOfArrays: Array<Array<Int>> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
|
||||
>
|
||||
```
|
||||
|
||||
如 [泛型形参子句](#generic_parameter) 所述,不能用泛型实参子句来指定泛型函数或构造器的类型实参。
|
||||
|
||||
@ -12,11 +12,16 @@ Swift 官方文档中文翻译由 [numbbbbb](https://github.com/numbbbbb) 发起
|
||||
- [DarrenChen123](https://github.com/DarrenChen123)
|
||||
- [dzyding](https://github.com/dzyding)
|
||||
- [Hale](https://github.com/wuqiuhao)
|
||||
- [Joeytat](https://github.com/joeytat)
|
||||
- [jojotov](https://github.com/jojotov)
|
||||
- [Khala-wan](https://github.com/Khala-wan)
|
||||
- [Nemocdz](https://github.com/Nemocdz)
|
||||
- [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)
|
||||
- [YiYiZheng](https://github.com/YiYiZheng)
|
||||
- [Yousanflics](https://github.com/Yousanflics)
|
||||
|
||||
## Swift 4.x 主要贡献者
|
||||
@ -143,4 +148,3 @@ Swift 官方文档中文翻译由 [numbbbbb](https://github.com/numbbbbb) 发起
|
||||
- [zqp](https://github.com/zqp)
|
||||
- [成都老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
||||
- [成都老码团队翻译组-Oberyn](http://weibo.com/u/5241713117)
|
||||
|
||||
|
||||
BIN
source/cover.jpg
BIN
source/cover.jpg
Binary file not shown.
|
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 576 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 20 KiB |
Reference in New Issue
Block a user