98 Commits
v2.1 ... v2.2

Author SHA1 Message Date
3fa3dd7af4 merge 2016-05-10 16:17:25 +08:00
667587bfca merge 2016-05-10 16:17:10 +08:00
16af2fa033 merge 2016-05-10 16:13:43 +08:00
6a9571cb8e 更新了语法变更历史内容 (#605)
* 1. 校对了翻译内容,删除了与 Swift 语言本身无关的相关变动
2. 页面内容适配为与 https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/RevisionHistory.html 相关的组织结构

* 1. 更新了 Swift 2.0 的相关语法变动
2. 更新了 Swift 2.1 的相关语法变动
3. 更新了 Swift 2.2 的相关语法变动
2016-05-09 20:51:13 +08:00
1502ff17f3 Update 04_Expressions.md 2016-05-08 11:35:00 +08:00
4685efc35d Update 04_Expressions.md
Fix some urls, add and correct some contents.
2016-05-08 11:31:16 +08:00
8234c6959b Merge pull request #603 from 949478479/gh-pages
Update 04_Expressions.md
2016-05-06 11:25:28 +08:00
fa6bc5c329 Update 04_Expressions.md 2016-05-06 10:58:59 +08:00
9267bf9c13 Merge pull request #602 from 949478479/gh-pages
Update 10_Statements.md
2016-05-05 08:26:34 +08:00
26c5b2ac9a Update 10_Statements.md 2016-05-04 23:40:54 +08:00
7110724b12 Merge pull request #601 from numbbbbb/release
Update CNAME
2016-04-28 10:54:26 +08:00
1801b6d920 Merge pull request #600 from SemperIdem/gh-pages
Declarations -> 2.2
2016-04-21 20:40:11 +08:00
e04533d2a8 Declarations -> 2.2 2016-04-21 13:22:21 +08:00
88befb0b59 Update README.md 2016-04-20 12:52:01 +08:00
dd265db62b Merge pull request #598 from Abitofcomedy/改错
改错
2016-04-20 12:51:24 +08:00
f270792d59 改错
类型方法代码写成static func 原文为 class func
2016-04-15 19:46:47 +08:00
8459508d67 update 2.2 history log date 2016-04-11 15:52:52 +08:00
42f3319e75 update 2.2 history log date 2016-04-11 15:51:03 +08:00
8bf061f8db Merge pull request #597 from saitjr/gh-pages
Fix format error
2016-04-11 10:15:42 +08:00
66c6e1287a fix format error 2016-04-11 09:58:22 +08:00
08838d2754 Merge pull request #596 from saitjr/gh-pages
Update to 2.2 (Properties)
2016-04-10 20:55:05 +08:00
b883da0fc2 proofreading 2016-04-10 20:07:24 +08:00
de0d455b03 add space 2016-04-10 19:22:17 +08:00
9522480e31 update to 2.2 2016-04-10 19:11:30 +08:00
11c71dbd52 Merge pull request #595 from Brian175/gh-pages
Update 02_a_swift_tour.md
2016-04-10 09:59:07 +08:00
556458dcb7 Update 02_a_swift_tour.md 2016-04-09 23:43:37 +08:00
93239d8927 update 2.2 history log date 2016-04-09 09:29:50 +08:00
cdf4de78d6 Update 23_Generics.md
update 2.2 history log
2016-04-09 09:26:42 +08:00
c625c336bc Merge pull request #594 from LanfordCai/develop
Updated Language Guide -- Generics
2016-04-08 14:42:20 +08:00
d6fd41d42d 校对 2016-04-08 14:18:39 +08:00
d415e542d9 Merge pull request #593 from SemperIdem/gh-pages
Language Reference - Lexical Structure
2016-04-06 15:59:51 +08:00
8aa9f9c591 Language Reference - Lexical Structure
Update to Swift 2.2
2016-04-06 12:10:26 +08:00
0bdce33f18 Merge pull request #590 from chenmingbiao/develop
update Language Reference - Statements
2016-04-05 14:39:20 +08:00
a403c3c38e Merge pull request #589 from LinusLing/gh-pages
update Control Flow
2016-04-05 14:39:13 +08:00
e2048a5bd6 Merge pull request #591 from Cee/gh-pages
Added information about comparing tuples.
2016-04-05 14:39:07 +08:00
53df155db4 Merge pull request #592 from futantan/develop
Language Reference - Attributes
2016-04-05 14:38:58 +08:00
1e58639fd4 Updated the discussion of the @objc attribute in the Declaration Attributes section to note that enumerations and enumeration cases can use this attribute. 2016-04-04 19:37:58 +08:00
Cee
2aece1573b Added information about comparing tuples. 2016-04-04 15:55:07 +08:00
63baf59044 update Language Reference - Statements 2016-04-03 17:02:09 +08:00
13ba7b263a update Language Reference - Statements 2016-04-03 16:55:44 +08:00
8063e80cd4 update Control Flow 2016-04-03 14:14:15 +08:00
ba7ce72dab Merge pull request #588 from colourful987/develop
update initialization
2016-04-03 07:19:25 +08:00
3984a8eba0 update initialization
delete 类的可失败构造器小节;update 构造失败的传递小节。
2016-04-02 23:35:39 +08:00
94e9ce8896 Update CNAME 2016-03-14 20:55:53 +08:00
6adcf58883 Merge pull request #586 from xinqiu/patch-1
这个地方用许多比较好
2016-03-14 12:24:02 +08:00
8038c724fd 这个地方用许多比较好
The contents of a String can be accessed in various ways
一个`String`的内容可以用许多方式读取.
way加了s,说明前面的various指的是多种。
2016-03-13 23:12:57 +08:00
673a930825 Update CNAME 2016-03-08 15:19:43 +08:00
a4d4563a3e Update README.md 2016-02-21 18:56:59 +08:00
6030252de2 Merge pull request #578 from 949478479/patch-1
根据评论反馈修改个别字词的翻译
2016-02-21 18:53:04 +08:00
2e699265cd 根据评论反馈修改个别字词的翻译 2016-02-06 04:45:24 +08:00
1183b3a790 Merge pull request #576 from Realank/gh-pages
[校对]校对"自动引用计数"章节
2016-01-28 13:10:24 +08:00
4b26824274 Merge remote-tracking branch 'numbbbbb/gh-pages' into gh-pages 2016-01-28 11:22:07 +08:00
8dca4a9691 [校对]“自动引用计数”章节翻译修改
[校对]“自动引用计数”章节翻译修改
2016-01-23 16:33:29 +08:00
af5190d20b Merge pull request #574 from Realank/gh-pages
修改构造器章节的问题
2016-01-23 09:29:10 +08:00
7fa09edc82 删除多余的字 2016-01-23 00:35:53 +08:00
b78c821847 修改"构造过程"章节错误 2016-01-23 00:30:43 +08:00
779529b4d3 修改格式 2016-01-21 16:59:16 +08:00
50593cc385 Merge pull request #573 from heqichang/develop
修改一处语句
2016-01-20 20:44:10 +08:00
fd2fbe9656 校对一处语句 2016-01-20 17:45:52 +08:00
3793e84c51 修改版本记录的纰漏 2016-01-20 09:55:04 +08:00
c1cad1243f 修改翻译和格式 2016-01-19 22:09:13 +08:00
5d26bb572b 修改格式 2016-01-19 21:29:42 +08:00
b8dd7477d0 修改格式 2016-01-19 21:26:02 +08:00
482e136e62 修改表述防止歧义 2016-01-19 21:10:08 +08:00
8301f0146a Merge pull request #572 from GithubChinaCH/develop
add end
2016-01-19 17:20:45 +08:00
64ea022b1b add end 2016-01-19 17:14:19 +08:00
d45fb7a362 Merge pull request #571 from overtrue-forks/gh-pages
“下标脚本“ -> “下标”
2016-01-19 10:48:59 +08:00
d78047411a 下标脚本 -> 下标 #570 2016-01-19 10:47:26 +08:00
1c031cc068 Merge pull request #570 from Realank/gh-pages
修改“下标脚本”为“下标”
2016-01-19 10:00:20 +08:00
3aae7178fe 修改“下标脚本”为“下标” 2016-01-19 09:43:16 +08:00
b51e163ad3 Merge pull request #569 from Realank/gh-pages
[校对]“闭包”~“方法”章节校对和翻译错误修改
2016-01-18 18:27:18 +08:00
42887ea878 修改“方法”章节的翻译错误 2016-01-18 17:19:05 +08:00
ea0fe35ec6 修改错误单词 2016-01-18 15:55:43 +08:00
ddc5308a78 Revert "删除不需要的日期"
This reverts commit 9cc876ef9c.
2016-01-18 13:47:42 +08:00
d150eb864b 规范化命名
Deinitializer=》析构器
2016-01-18 13:20:33 +08:00
9cc876ef9c 删除不需要的日期 2016-01-18 11:30:24 +08:00
6dcaac7e3f 修改错字 2016-01-18 09:26:03 +08:00
50e0d61d7a Merge pull request #568 from qinix/fix-typo
fixed a typo
2016-01-15 17:29:56 +08:00
1a38c70cb3 fixed a typo 2016-01-15 15:55:49 +08:00
9f9c8e9bea Merge pull request #567 from Realank/gh-pages
[校对]"字符串和字符"、"集合类型"等章节校对
2016-01-15 11:02:41 +08:00
999d92438f 优化表达 2016-01-15 07:52:45 +08:00
4dcc7205a2 替换绕口语句
这句话有点绕口,换一种表达
2016-01-15 07:45:11 +08:00
30638918c3 删除多余的字 2016-01-15 07:29:35 +08:00
d3e873f2b4 修改病句 2016-01-14 20:38:12 +08:00
9dc335493e 修正集合类型章节的错误 2016-01-14 20:03:11 +08:00
908b206f33 修正错误
叹号后面应该有空格的
2016-01-14 17:19:10 +08:00
64d9b13501 添加署名 2016-01-14 16:22:00 +08:00
c470ad343e 修改表格标题错误 2016-01-14 16:09:42 +08:00
1472d14d63 修改描述不准确
“ which is a collection of values of type UnicodeScalar.”
这里描述不准确
2016-01-14 16:07:36 +08:00
88ecb81a47 修改错误字符
小狗字符错显示成了?乱码,开头几个字符用逗号隔开可读性更强,就像英文版一样
2016-01-14 16:00:13 +08:00
ba6f7a207e 修改刚刚修改的错误
多了几个括号
2016-01-14 15:55:31 +08:00
b15859e7d1 调整格式
定义类名次,加上``引用和英文描述
2016-01-14 15:54:02 +08:00
a6cd183aba 修改防止歧义
使用地域更易理解,不然容易与之前的索引混淆,并且加上英文原文
2016-01-14 15:47:12 +08:00
e863958b5b 内容错误
terminator不应该有空格,否则每个单词之间会有两个空格,英文版也没有空格
2016-01-14 15:39:25 +08:00
781c484681 修改翻译
“You access and modify a string through its methods and properties”
翻译不准确,并且少了一个字“通”
2016-01-14 15:21:34 +08:00
86a67b7545 修改翻译
REGIONAL应该翻译为地域性
2016-01-14 15:16:28 +08:00
716a0d08eb 修改类型描述
虽然英文原文是“its Boolean isEmpty property”,但是按照翻译的语义,应该是指的具体返回值的类型Bool
2016-01-14 13:57:00 +08:00
4c22e27a11 Markdown 格式修正. 2016-01-05 20:47:23 +08:00
29 changed files with 2768 additions and 2803 deletions

2
CNAME
View File

@ -1 +1 @@
www.swiftguide.cn
gg.swiftguide.cn

View File

@ -1,7 +1,7 @@
《The Swift Programming Language》in Chinese
=============================================
中文版Apple官方Swift教程《The Swift Programming Language》
中文版 Apple 官方 Swift 教程《The Swift Programming Language》
[英文原版](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/index.html#//apple_ref/doc/uid/TP40014097-CH3-ID0)
@ -9,17 +9,17 @@
# 在线阅读
使用Gitbook制作可以直接[在线阅读](http://swiftguide.cn/)。
使用 Gitbook 制作,可以直接[在线阅读](http://swiftguide.cn/)。
# 当前阶段
已经更新到Swift 2.1
已经更新到 Swift 2.2
# 2.1译者记录
# 2.1 & 2.2 译者记录
详见各章节开头位置。
# 2.0译者记录
# 2.0 译者记录
- About Swift [xtymichael](https://github.com/xtymichael)
- A Swift Tour[xtymichael](https://github.com/xtymichael)
@ -59,7 +59,7 @@
- Generic Parameters and Arguments[wardenNScaiyi](https://github.com/wardenNScaiyi)
- Summary of the Grammar[miaosiqi](https://github.com/miaosiqi)
# 1.0译者记录
# 1.0 译者记录
* 欢迎使用 Swift
* 关于 Swift ([numbbbbb])

View File

@ -76,7 +76,7 @@ println(sayHelloAgain("Anna"))
func halfOpenRangeLength(start: Int, end: Int) -> Int {
return end - start
}
println(halfOpenRangeLength(1, 10))
println(halfOpenRangeLength(1, end:10))
// prints "9"
```

View File

@ -1,4 +1,4 @@
> 已同步更新到 Swift 2.1
> 已同步更新到 Swift 2.2
# 2.0 新的开始
@ -71,5 +71,6 @@ Swift 2.0 参与者名单(按照章节顺序):
- [ray16897188](https://github.com/ray16897188)
- [wardenNScaiyi](https://github.com/wardenNScaiyi)
- [miaosiqi](https://github.com/miaosiqi)
- [Realank](https://github.com/Realank)
最后,感谢[极客学院](http://wiki.jikexueyuan.com)提供的wiki系统在国内访问起来速度很快优化后的样式看起来也更舒服。
最后,感谢[极客学院](http://wiki.jikexueyuan.com)提供的wiki系统在国内访问起来速度很快优化后的样式看起来也更舒服。

View File

@ -17,7 +17,7 @@
* [类和结构体](chapter2/09_Classes_and_Structures.md)
* [属性](chapter2/10_Properties.md)
* [方法](chapter2/11_Methods.md)
* [下标脚本](chapter2/12_Subscripts.md)
* [下标](chapter2/12_Subscripts.md)
* [继承](chapter2/13_Inheritance.md)
* [构造过程](chapter2/14_Initialization.md)
* [析构过程](chapter2/15_Deinitialization.md)

View File

@ -9,6 +9,9 @@
> 2.0
> 翻译+校对:[xtymichael](https://github.com/xtymichael)
> 2.2
> 翻译:[175](https://github.com/Brian175)2016-04-09
本页内容包括:
- [简单值Simple Values](#simple_values)
@ -17,6 +20,7 @@
- [对象和类Objects and Classes](#objects_and_classes)
- [枚举和结构体Enumerations and Structures](#enumerations_and_structures)
- [协议和扩展Protocols and Extensions](#protocols_and_extensions)
- [错误处理Error Handling](#error_handling)
- [泛型Generics](#generics)
通常来说编程语言教程中的第一个程序应该在屏幕上打印“Hello, world”。在 Swift 中,可以用一行代码实现:
@ -30,8 +34,7 @@ print("Hello, world!")
这个教程会通过一系列编程例子来让你对 Swift 有初步了解,如果你有什么不理解的地方也不用担心——任何本章介绍的内容都会在后面的章节中详细讲解。
> 注意:
> 为了获得最好的体验,在 Xcode 当中使用代码预览功能。代码预览功能可以让你编辑代码并实时看到运行结果。
> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.playground.zip">下载Playground</a>
> 在 Mac 上,下载 Playground 并双击文件在 Xcode 里打开:[https://developer.apple.com/go/?id=swift-tour](https://developer.apple.com/go/?id=swift-tour)
<a name="simple_values"></a>
## 简单值
@ -212,20 +215,14 @@ repeat {
print(m)
```
你可以在循环中使用`..<`来表示范围,也可以使用传统的写法,两者是等价的:
你可以在循环中使用`..<`来表示范围
```swift
var firstForLoop = 0
var total = 0
for i in 0..<4 {
firstForLoop += i
total += i
}
print(firstForLoop)
var secondForLoop = 0
for var i = 0; i < 4; ++i {
secondForLoop += i
}
print(secondForLoop)
print(total)
```
使用`..<`创建的范围不包含上界,如果想包含的话需要使用`...`
@ -540,7 +537,7 @@ let aceRawValue = ace.rawValue
> 练习:
> 写一个函数,通过比较它们的原始值来比较两个`Rank`值。
在上面的例子中,枚举原始值的类型是`Int`,所以你只需要设置第一个原始值。剩下的原始值会按照顺序赋值。你也可以使用字符串或者浮点数作为枚举的原始值。使用`rawValue`属性来访问一个枚举成员的原始值。
默认情况下Swift 按照从 0 开始每次加 1 的方式为原始值进行赋值,不过你可以通过显式赋值进行改变。在上面的例子中,`Ace`被显式赋值为 1并且剩下的原始值会按照顺序赋值。你也可以使用字符串或者浮点数作为枚举的原始值。使用`rawValue`属性来访问一个枚举成员的原始值。
使用`init?(rawValue:)`初始化构造器在原始值和枚举值之间进行转换。
@ -601,17 +598,17 @@ let threeOfSpadesDescription = threeOfSpades.simpleDescription()
```swift
enum ServerResponse {
case Result(String, String)
case Error(String)
case Failure(String)
}
let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")
let failure = ServerResponse.Failure("Out of cheese.")
switch success {
case let .Result(sunrise, sunset):
let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
case let .Error(error):
let serverResponse = "Failure... \(error)"
case let .Failure(message):
print("Failure... \(message)")
}
```
@ -689,6 +686,88 @@ print(protocolValue.simpleDescription)
即使`protocolValue`变量运行时的类型是`simpleClass`,编译器会把它的类型当做`ExampleProtocol`。这表示你不能调用类在它实现的协议之外实现的方法或者属性。
<a name="error_handling"></a>
## 错误处理
使用采用`ErrorType`协议的类型来表示错误。
```swift
enum PrinterError: ErrorType {
case OutOfPaper
case NoToner
case OnFire
}
```
使用`throw`来抛出一个错误并使用`throws`来表示一个可以抛出错误的函数。如果在函数中抛出一个错误,这个函数会立刻返回并且调用该函数的代码会进行错误处理。
```swift
func sendToPrinter(printerName: String) throws -> String {
if printerName == "Never Has Toner" {
throw PrinterError.NoToner
}
return "Job sent"
}
```
有多种方式可以用来进行错误处理。一种方式是使用`do-catch`。在`do`代码块中,使用`try`来标记可以抛出错误的代码。在`catch`代码块中,除非你另外命名,否则错误会自动命名为`error`
```swift
do{
let printerResponse = try sendToPrinter("Bi Sheng")
print(printerResponse)
} catch {
print(error)
}
```
> 练习:
> 将 printer name 改为`"Never Has Toner"`使`sendToPrinter(_:)`函数抛出错误。
可以使用多个`catch`块来处理特定的错误。参照 switch 中的`case`风格来写`catch`
```swift
do {
let printerResponse = try sendToPrinter("Gutenberg")
print(printerResponse)
} catch PrinterError.OnFire {
print("I'll just put this over here, with the rest of the fire.")
} catch let printerError as PrinterError {
print("Printer error: \(printerError).")
} catch {
print(error)
}
```
> 练习:
> 在`do`代码块中添加抛出错误的代码。你需要抛出哪种错误来使第一个`catch`块进行接收?怎么使第二个和第三个`catch`进行接收呢?
另一种处理错误的方式使用`try?`将结果转换为可选的。如果函数抛出错误,该错误会被抛弃并且结果为`nil`。否则的话,结果会是一个包含函数返回值的可选值。
```swift
let printerSuccess = try? sendToPrinter("Mergenthaler")
let printerFailure = try? sendToPrinter("Never Has Toner")
```
使用`defer`代码块来表示在函数返回前,函数中最后执行的代码。无论函数是否会抛出错误,这段代码都将执行。使用`defer`,可以把函数调用之初就要执行的代码和函数调用结束时的扫尾代码写在一起,虽然这两者的执行时机截然不同。
```swift
var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]
func fridgeContains(itemName: String) -> Bool {
fridgeIsOpen = true
defer {
fridgeIsOpen = false
}
let result = fridgeContent.contains(itemName)
return result
}
fridgeContains("banana")
print(fridgeIsOpen)
```
<a name="generics"></a>
## 泛型

View File

@ -1,37 +1,44 @@
# Swift 版本历史记录
# Swift 文档修订历史
---
> 1.0
> 翻译:[成都老码团队翻译组-Arya](http://weibo.com/littlekok/)
> 校对:[成都老码团队翻译组-Oberyn](http://weibo.com/u/5241713117)
[changkun](http://changkun.us/about/)
>
> 1.1
> 翻译:[成都老码团队翻译组-Arya](http://weibo.com/littlekok/)
> 校对:[成都老码团队翻译组-Oberyn](http://weibo.com/u/5241713117)
[changkun](http://changkun.us/about/)
>
> 1.2
> 翻译:[成都老码团队翻译组-Arya](http://weibo.com/littlekok/)
> 校对:[成都老码团队翻译组-Oberyn](http://weibo.com/u/5241713117)
[changkun](http://changkun.us/about/)
>
> 2.0
> 翻译+校对:[changkun](http://changkun.us/about/)
>
> 2.1
> 翻译+校对:[changkun](http://changkun.us/about/)
>
> 2.2
> 翻译+校对:[changkun](http://changkun.us/about/)
本页面根据 [Document Revision History](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/RevisionHistory.html) 进行适配更新。
本页内容包括:
- [XCode6.4 Beta Swift语法文档更新](#xcode6_4_Beta)
- [XCode6.3正式版 Swift语法文档更新](#xcode6_3)
- [XCode6.2正式版 Swift语法文档更新](#xcode6_2)
- [XCode6.2 Beta3 Swift语法文档更新](#xcode6_2_Beta3)
- [XCode6.2 Beta2 Swift语法文档更新](#xcode6_2_Beta2)
- [XCode6.2 Beta1 Swift语法文档更新](#xcode6_2_Beta1)
- [XCode6.1.1正式版 Swift语法文档更新](#xcode6_1_1)
- [XCode6.1 Swift语法文档更新](#xcode6_1)
- [XCode6.1 Beta2 Swift语法文档更新](#xcode6_1_Beta2)
- [XCode6.1 Beta1 Swift语法文档更新](#xcode6_1_Beta1)
- [XCode6 Beta7 Swift语法文档更新](#xcode6_beta7)
- [XCode6 Beta6 Swift语法文档更新](#xcode6_beta6)
- [XCode6 Beta5 Swift语法文档更新](#xcode6_beta5)
- [XCode6 Beta4 Swift语法文档更新](#xcode6_beta4)
- [XCode6 Beta3 Swift语法文档更新](#xcode6_beta3)
- [XCode6 Beta2 Swift语法文档更新](#xcode6_beta2)
- [XCode6 Beta1 Swift语法文档更新](#xcode6_beta1)
- XCode6下载: [老码云盘下载](http://pan.baidu.com/disk/home#from=share_pan_logo&path=%252F%25E8%2580%2581%25E7%25A0%2581%25E4%25BA%2591%25E7%259B%2598-XCode6%252FXCode6-Beta5)
- [Swift 2.2 更新](#swift_2_2)
- [Swift 2.1 更新](#swift_2_1)
- [Swift 2.0 更新](#swift_2_0)
- [Swift 1.2 更新](#swift_1_2)
- [Swift 1.1 更新](#swift_1_1)
- [Swift 1.0 更新](#swift_1_0)
以下部分是针对XCode6每一次Beta版本直至正式版发布Swift语法部分的更新归类
<a name="xcode6_4_Beta"></a>
### XCode6.4 Beta中Swift语法更新
***注意苹果在这个版本发布后没有及时的更新Swift Programming Language文档,以下是[老码团队](http://weibo.com/u/5241713117)通过XCode6.4 Beta Release Note总结的更改说明***
<a name="swift_2_2"></a>
### Swift 2.2 更新
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
@ -42,10 +49,55 @@
</thead>
<tbody>
<tr>
<td scope="row">2015-04-13</td>
<td scope="row">2016-03-21</td>
<td><ul class="list-bullet">
<li>
XCode6.4包含了对于构建和调试基于iOS8.4 App的支持
更新至 Swift 2.2。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID539">编译配置语句</a>一节中关于如何根据 Swift 版本进行条件编译。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID400">显示成员表达式</a>一节中关于如何区分只有参数名不同的方法和构造器的信息。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID547">选择器表达式</a>一节中针对 Objective-C 选择器的 <code>#selector</code> 语法。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-ID189">关联类型</a><a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID374">协议关联类型</a>声明,使用 <code>associatedtype</code> 关键词修改了对于关联类型的讨论。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-ID224">可失败构造器</a>一节中关于当构造器在实例完全初始化之前返回 <code>nil</code>的相关信息。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-ID70">比较运算符</a>一节中关于比较元组的信息。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID413">关键字和标点符号</a>一节中关于使用关键字作为外部参数名的信息。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID413">声明特性</a>一节中关于<code>@objc</code>特性的讨论,并指出枚举(Enumeration)和枚举用例(Enumaration Case)。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID418">操作符</a>一节中对于自定义运算符的讨论包含了<code>.</code>
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID531">重新抛出错误的函数和方法</a>一节中关于重新抛出错误函数不能直接抛出错误的笔记。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID262">属性观察器</a>一节中关于当作为 in-out 参数传递属性时,属性观察器的调用行为。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-ID1">Swift 初见</a>一节中关于错误处理的内容。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID53">弱引用</a>一节中的图片用以更清楚的展示重新分配过程。
</li>
<li>
删除了 C 语言风格的 <code>for</code> 循环,<code>++</code> 前缀和后缀运算符,以及<code>--</code> 前缀和后缀运算符。
</li>
<li>
删除了对变量函数参数和柯里化函数的特殊语法的讨论。
</li>
</ul>
</td>
@ -53,9 +105,195 @@
</tbody>
</table>
<a name="swift_2_1"></a>
### Swift 2.1 更新
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2015-10-20</td>
<td><ul class="list-bullet">
<li>
更新至 Swift 2.1。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID292">字符串插值(String Interprolation)</a><a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID417">字符串字面量(String Literals)</a>小节,现在字符串插值可包含字符串字面量。
</li>
<li>
增加了在<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID546">非逃逸闭包(Nonescaping Closures)</a>一节中关于 <code>@noescape</code> 属性的相关内容。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Attributes.html#//apple_ref/doc/uid/TP40014097-CH35-ID348">声明特性(Declaration Attributes)</a><a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID539">编译配置语句(Build Configuration Statement)</a>小节中与 tvOS 相关的信息。
</li>
<li>
增加了 <a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID545">In-Out 参数(In-Out Parameters)</a>小节中与 in-out 参数行为相关的信息。
</li>
<li>
增加了在<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID544">捕获列表(Capture Lists)</a>一节中关于指定闭包捕获列表被捕获时捕获值的相关内容。
</li>
<li>
更新了通过<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html#//apple_ref/doc/uid/TP40014097-CH21-ID248">可选链式调用访问属性(Accessing Properties Through Optional Chaining)</a>一节,阐明了如何通过可选链式调用进行赋值。
</li>
<li>
改进了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID543">自闭包(Autoclosure)</a>一节中对自闭包的讨论。
</li>
<li>
<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-ID1">Swift 初见(A Swift Tour)</a>一节中更新了一个使用<code>??</code>操作符的例子。
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="swift_2_0"></a>
### Swift 2.0 更新
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2015-09-16</td>
<td><ul class="list-bullet">
<li>
更新至 Swift 2.0。
</li>
<li>
增加了对于错误处理相关内容,包括 <a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html#//apple_ref/doc/uid/TP40014097-CH42-ID508">错误处理</a>一章、<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID533">Do 语句</a><a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID518">Throw 语句</a><a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID532">Defer 语句</a>以及<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID516">try 运算符</a> 的多个小节。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html#//apple_ref/doc/uid/TP40014097-CH42-ID509">表示并抛出错误</a>一节,现在所有类型均可遵循 <code>ErrorType</code> 协议。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html#//apple_ref/doc/uid/TP40014097-CH42-ID542">将错误转换成可选值</a>一节 <code>try?</code> 关键字的相关信息。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID145">枚举</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID536">递归枚举</a>一节和<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID351">声明</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID365">任意类型用例的枚举</a>一节中关于递归枚举的内容。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID120">控制流</a>一章中a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID523">检查 API 可用性</a>一节和<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID428">语句</a>一章中<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID522">可用性条件</a>一节中关于 API 可用性检查的内容。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID120">控制流</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID525">早期退出</a>一节和<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID428">语句</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID524">guard语句</a>中关于新 <code>guard</code> 语句的内容。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID267">协议</a>一章中<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID521">协议扩展</a>一节中关于协议扩展的内容。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html#//apple_ref/doc/uid/TP40014097-CH41-ID3">访问控制</a>一章中<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html#//apple_ref/doc/uid/TP40014097-CH41-ID519">单元测试 target 的访问级别</a>一节中关于单元测试的访问控制相关的内容。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/doc/uid/TP40014097-CH36-ID419">模式</a>一章中<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/doc/uid/TP40014097-CH36-ID520">可选模式</a>一节中的新可选模式。
</li>
<li>
更新了 <a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID126">Repeat-While</a> 一节中关于<code>repeat-while</code>循环的信息。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID285">字符串和字符</a>一章,现在<code>String</code>在 Swift 标准库中不再遵循<code>CollectionType</code>协议。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID314">打印常量和变量</a>一节中关于新 Swift 标准库中关于 <code>print(_:separator:terminator)</code> 的信息。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID145">枚举</a>一章中<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID535">原始值的隐式赋值</a>一节和<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID351">声明</a>一章的<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID366">包含原始值类型的枚举</a>一节中关于包含<code>String</code>原始值的枚举用例的行为。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID543">自闭包</a>一节中关于<code>@autoclosure</code>特性的相关信息,包括它的<code>@autoclosure(escaping)</code>形式。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Attributes.html#//apple_ref/doc/uid/TP40014097-CH35-ID348">声明特性</a>一节中关于<code>@avaliable</code><code>warn_unused_result</code>特性的相关内容。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Attributes.html#//apple_ref/doc/uid/TP40014097-CH35-ID350">类型特性</a>一节中关于<code>@convention</code>特性的相关信息。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID333">可选绑定</a>一节中关于使用<code>where</code>子句进行多可选绑定的内容。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID292">字符串字面量</a>一节中关于在编译时使用 <code>+</code> 运算符凭借字符串字面量的相关信息。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID455">元类型</a>一节中关于元类型值的比较和使用它们通过构造器表达式构造实例。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID336">断言调试</a>一节中关于用户定义断言是被警用的相关内容。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Attributes.html#//apple_ref/doc/uid/TP40014097-CH35-ID348">声明特性</a>一节中,对<code>@NSManaged</code>特性的讨论,现在这个特性可以被应用到一个确定实例方法。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html#//apple_ref/doc/uid/TP40014097-CH10-ID171">可变参数</a>一节,现在可变参数可以声明在函数参数列表的任意位置中。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-ID229">重写可失败构造器</a>一节中,关于非可失败构造器相当于一个可失败构造器通过父类构造器的结果进行强制拆包的相关内容。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID365">任意类型用例的枚举</a>一节中关于枚举用例作为函数的内容。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID399">构造器表达式</a>一节中关于显式引用一个构造器的内容。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID538">编译控制语句</a>一节中关于编译信息以及行控制语句的相关信息。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID455">元类型</a>一节中关于如何从元类型值中构造类实例。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID53">弱引用</a>一节中关于弱引用作为缓存的显存的不足。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID292">类型特性</a>一节,提到了存储型特性其实是懒加载。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID264">捕获类型</a>一节,阐明了变量和常量在闭包中如何被捕获。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Attributes.html#//apple_ref/doc/uid/TP40014097-CH35-ID348">声明特性</a>一节用以描述如何在类中使用<code>@objc</code>关键字。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html#//apple_ref/doc/uid/TP40014097-CH42-ID512">错误处理</a>一节中关于执行<code>throw</code>语句的性能的讨论。增加了 Do 语句一节中相似的信息。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID533">类型特性</a>一节中关于类、结构体和枚举的存储型和计算型特性的信息。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID441">Break 语句</a>一节中关于带标签的 break 语句。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID262">属性观察器</a>一节,阐明了<code>willSet</code><code>didSet</code>观察器的行为。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html#//apple_ref/doc/uid/TP40014097-CH41-ID5">访问级</a>一节中关于<code>private</code>作用域访问的相关信息。
</li>
<li>
增加了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID53">弱引用</a>一节中关于若应用在垃圾回收系统和 ARC 之间的区别。
</li>
<li>
更新了<a href="https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID295">字符串字面量中特殊字符</a>一节中对 Unicode 标量更精确的定义。
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="swift_1_2"></a>
### Swift 1.2 更新
<a name="xcode6_3"></a>
### XCode6.3中Swift语法更新
***注意苹果此时发布了统一的版本XCode6.3其中将以前的XCode6.3 Beta系列版本合并, 而XCode6.3共计发布了4次Beta版本[老码团队](http://weibo.com/u/5241713117)通过Release Note总结的详细更改说明请参看:[Swift语法更新记录表格](https://docs.baihui.com/sheet/published.do?rid=mxpis6d36a8b7bc254c36ae2a808c64c2361e)***
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
@ -68,6 +306,9 @@
<tr>
<td scope="row">2015-4-8</td>
<td><ul class="list-bullet">
<li>
更新至 Swift 1.2。
</li>
<li>
Swift现在自身提供了一个<code>Set</code>集合类型,更多信息请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-ID484">集合</a>
@ -85,7 +326,7 @@
增加了一个新的指导章节,它是关于<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID495">字符串索引</a>
</li>
<li>
<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-ID37">溢出运算符</a>中移除了溢出除运算符和求余溢出运算符
<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-ID37">溢出运算符</a>中移除了溢出除运算符(&/)和求余溢出运算符(&%)。
</li>
<li>
更新了常量和常量属性在声明和构造时的规则,更多信息,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID355">常量声明</a>
@ -111,29 +352,7 @@
<li>
更新了<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID418">运算符</a>章节来明确指明一些例子来说明自定义运算符所支持的特性如数学运算符各种符号Unicode符号块等
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_2"></a>
### XCode6.2正式版中Swift语法更新
***注意苹果此时发布了统一的版本XCode6.2其中将以前的XCode6.2 Beta系列版本合并***
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2015-02-09</td>
<td><ul class="list-bullet">
<li>
<li>
在函数作用域中的常量声明时可以不被初始化,它必须在第一次使用前被赋值。更多的信息,请看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID355">常量声明</a>
</li>
<li>
@ -157,139 +376,9 @@
</tbody>
</table>
<a name="xcode6_2_Beta3"></a>
### XCode6.2 Beta3中Swift语法更新
***注意苹果在这个版本发布后没有及时的更新Swift Programming Language文档,以下是[老码团队](http://weibo.com/u/5241713117)通过XCode6.2 Beta3 Release Note总结的更改说明***
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-12-19</td>
<td>
<ul class="list-bullet">
<li>
在对Watch App做消息通知模拟调试时第一个payload.apns文件将会被默认选择
</li>
<li>
在为Watch App使用asset catalog时38mm和42mm尺寸的图片就会被使用
</li>
<li>
在做Watch App开发时,<code>@IBAction</code>属性支持<code>WKInterfaceSwitch</code><code>WKInterfaceSlider</code> Swift类型了
</li>
<li>
现在可以通过Device窗口安装删除和访问App容器中的数据了。
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_2_Beta2"></a>
### XCode6.2 Beta2中Swift语法更新
***注意苹果在这个版本发布后没有及时的更新Swift Programming Language文档,以下是[老码团队](http://weibo.com/u/5241713117)通过XCode6.2 Beta2 Release Note总结的更改说明***
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-12-10</td>
<td><ul class="list-bullet">
<li>
现在在Interface Builder中可以针对特定的Device设备自定义Watch应用的Layout布局了
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_2_Beta1"></a>
### XCode6.2 Beta1中Swift语法更新
***注意苹果在这个版本发布后没有及时的更新Swift Programming Language文档,以下是[老码团队](http://weibo.com/u/5241713117)通过XCode6.2 Beta1 Release Note总结的更改说明***
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-11-28</td>
<td><ul class="list-bullet">
<li>
XCode6.2包含了iOS8.2 SDK该SDK中包含WatchKit用来开发Apple Watch应用。
</li>
<li>
在工具集中增加了对WatchKit的支持
1UI设计工具增加了Apple Watch应用的界面组件通知和小部件。
2增加了调试和性能统计功能
3增加Apple Watch应用的模拟器帮助调试应用功能
</li>
<li>
为了使Apple Watch应用能够正常工作一些具体的参数必须设置
1WatchKit中扩展配置文件Info.plist中的<code>NSExtensionAttributes</code>配置项WKAppBundleIdentifier必须和WatchKit App中的通用配置文件中的属性<code>CFBundleIdentifier</code>项目保持一致。2WatchKit中的<code>CFBundleIdentifier</code>配置项必须和<code>WKCompanionAppBundleIdentifier</code>中的配置项保持一致
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_1_1"></a>
### XCode6.1.1中Swift语法更新
***注意苹果在这个版本发布后没有及时的更新Swift Programming Language文档,以下是[老码团队](http://weibo.com/u/5241713117)通过XCode6.1.1 Release Note总结的更改说明***
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-12-2</td>
<td><ul class="list-bullet">
<li>
在SourceKit中一些导致Crash的常见问题被修复比如名字冲突和遗留废弃数据的问题等。
</li>
<li>
把纯正的Swift类对象实例赋值给AnyObject量不会再Crash了。
</li>
<li>
在泛型使用场景下,遵循了协议类要求的构造器方法或者类型方法可以直接调用继承类中的方法了。
</li>
<li>
修正了InterfaceBuild中如果图片名字含有“/”时会在OSX10.10上Crash或者无法打开的问题
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_1"></a>
### XCode6.1中Swift语法更新
***注意苹果此时发布了统一的版本XCode6.1其中将以前的XCode6.0.1和XCode6.1 Beta系列版本合并***
<a name="swift_1_1"></a>
### Swift 1.1 更新
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
@ -303,112 +392,32 @@
<td scope="row">2014-10-16</td>
<td><ul class="list-bullet">
<li>
增加了一个完整的关于<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html">失败构造器(Failable Initializers)</a>的指南文档
更新至 Swift 1.1。
</li>
<li>
增加了一个关于协议的<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html">失败构造器需求(Failable Initializer Requirements)</a>描述
增加了关于<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html">失败构造器(Failable Initializers)</a>完整章节。
</li>
<li>
`Any`类型的常量或变量现在可以包含一个函数实例了。同时更新了<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html">`Any`</a>章节的案例用来演示如何在swith语句中检查和转换一个函数类型
增加了协议中关于失败构造器要求的描述
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_1_Beta2"></a>
### XCode6.1 Beta2中Swift语法更新
***注意苹果此时发布了XCode6.0.1版本(也称为XCode6正式版)此版本用于iOS的开发同时也发布子版本XCode6.1 Beta2此版本为OSX开发做准备以下所述的更改仅对XCode6.1 Beta2有效***
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-09-15</td>
<td><ul class="list-bullet">
<li>
带有原始值的枚举类型增加了一个<code>rawValue</code>属性替代<code>toRaw()</code>方法,同时使用了一个以<code>rawValue</code>为参数的失败构造器来替代<code>fromRaw()</code>方法。更多的信息,请看<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html">原始值(Raw Values)</a><a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html">带原始值的枚举类型(Enumerations with Cases of a Raw-Value Type)</a>部分
常量和变量的 <code>Any</code> 类型现可以包含函数实例。更新了关于 <code>Any</code> 相关的示例来展示如何在 <code>switch</code> 语句中如何检查并转换到一个函数类型。
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_1_Beta1"></a>
### XCode6.1 Beta1中Swift语法更新
***注意苹果此时发布了XCode6 GM版本此版本用于iOS的开发同时也发布子版本XCode6.1 Beta1此版本为OSX开发做准备以下所述的更改仅对XCode6.1 Beta1有效***
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-09-09</td>
<td><ul class="list-bullet">
<li>
增加了一个新的关于<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html">失败构造器(Failable Initializers)</a>的参考章节,失败构造器可以触发失败的构造过程
带有原始值的枚举类型增加了一个<code>rawValue</code>属性替代<code>toRaw()</code>方法,同时使用了一个以<code>rawValue</code>为参数的失败构造器来替代<code>fromRaw()</code>方法。更多的信息,请看<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html">原始值(Raw Values)</a><a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html">带原始值的枚举类型(Enumerations with Cases of a Raw-Value Type)</a>部分。
</li>
<li>
自定义运算符现在可以包含`?`字符,更新的<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html">运算符(Operators)</a>章节描述了改进后的规则,并且从<a href="http://developer.apple.com/library/etc/redirect/xcode/devtools/419f35/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html">自定义运算符(Custom Operators)</a>章节删除了重复的运算符有效字符集合
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_beta7"></a>
### XCode6 Beta7中Swift语法更新
***注意苹果在这个版本发布后没有及时的更新Swift Programming Language文档,以下是[老码团队](http://weibo.com/u/5241713117)通过XCode Beta7 Release Note总结的更改说明***
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-09-03</td>
<td><ul class="list-bullet">
<li>
实现了内部库的修改和适配,主要包括如下:
1大量内部类或者函数遵循Optional类型和协议
2移除大部分函数返回类型隐式解封可选类型的使用
</li>
<li>
对于泛型的类库函数或接口统一从<code>T!</code>更换为<code>T</code><code>T</code>,这样使得语法更加严谨,明确了可能返回为空和不为空的情况
</li>
<li>
字符类型不能使用+运算法链接,可以以<code>String(C1)+String(2)</code> 的方式实现字符间链接
</li>
<li>
重写了<code>Sort</code>函数,解决了栈溢出的问题
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_beta6"></a>
### XCode6 Beta6中Swift语法更新
<a name="swift_1_0"></a>
### Swift 1.0 更新
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
@ -421,6 +430,9 @@
<tr>
<td scope="row">2014-08-18</td>
<td><ul class="list-bullet">
<li>
发布新的文档用以详述 Swift 1.0苹果公司针对iOS和OS X应用的全新开发语言。
</li>
<li>
在章节协议中,增加新的小节:<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_397">对构造器的规定Initializer Requirements</a>
</li>
@ -436,26 +448,6 @@
<li>
<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Attributes.html#//apple_ref/doc/uid/TP40014097-CH35-XID_516">声明特性Declaration Attributes</a>章节增加了关于<code>availability</code>特性的一些信息
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_beta5"></a>
### XCode6 Beta5中Swift语法更新
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-08-04</td>
<td><ul class="list-bullet">
<li>
<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_478">可选类型Optionals</a> 若有值时,不再隐式的转换为 <code>true</code>,同样,若无值时,也不再隐式的转换为 <code>false</code>, 这是为了避免在判别 optional <code>Bool</code> 的值时产生困惑。 替代的方案是,用<code>==</code><code>!=</code> 运算符显式地去判断Optinal是否是 <code>nil</code>,以确认其是否包含值。
</li>
@ -510,26 +502,6 @@
<li>
为章节<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_597">Curried Functions</a>添加了更多的信息.
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_beta4"></a>
#### XCode6 Beta4中Swift语法更新
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-07-21</td>
<td><ul class="list-bullet">
<li>
加入新的章节 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html#//apple_ref/doc/uid/TP40014097-CH41-XID_29">权限控制Access Control</a>.
</li>
@ -572,26 +544,6 @@
<li>
<code>nil</code> 和布尔运算中的 <code>true</code><code>false</code> 现在被定义为字面量<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_886">Literals</a>.
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_beta3"></a>
#### XCode6 Beta3中Swift语法更新
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-07-7</td>
<td><ul class="list-bullet">
<li>
Swift 中的数组 <code>Array</code> 类型从现在起具备了完整的值语义。具体信息被更新到 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-XID_170">集合的可变性Mutability of Collections</a><a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-XID_172">数组Arrays</a> 两小节,以反映这个新的变化. 此外,还解释了如何 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_150">给Strings, Arrays和Dictionaries进行赋值和拷贝 Assignment and Copy Behavior for Strings, Arrays, and Dictionaries</a>.
</li>
@ -616,52 +568,6 @@
<li>
添加一个例子 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-XID_285">扩展一个泛型Extending a Generic Type</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_beta2"></a>
#### XCode6 Beta2中Swift语法更新
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-07-7</td>
<td><ul class="list-bullet">
<li>
发布新的文档用以详述Swift - 苹果公司针对iOS和OS X应用的全新开发语言
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<a name="xcode6_beta1"></a>
#### XCode6 Beta1中Swift语法更新
<table class="graybox" border="0" cellspacing="0" cellpadding="5">
<thead>
<tr>
<th scope="col" width="100">发布日期</th>
<th scope="col">语法变更记录</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">2014-06-3</td>
<td><ul class="list-bullet">
<li>
苹果全球开发者大会WWDC2014召开发布了苹果最新的开发语言Swift并释放出XCode6 Beta1版本
</li>
</ul>
</td>
</tr>

View File

@ -546,7 +546,7 @@ print("The status message is \(http200Status.description)")
> 注意:
C 和 Objective-C 中并没有可选类型这个概念。最接近的是 Objective-C 中的一个特性,一个方法要不返回一个对象要不返回`nil``nil`表示“缺少一个合法的对象”。然而,这只对对象起作用——对于结构体,基本的 C 类型或者枚举类型不起作用。对于这些类型Objective-C 方法一般会返回一个特殊值(比如`NSNotFound`来暗示值缺失。这种方法假设方法的调用者知道并记得对特殊值进行判断。然而Swift 的可选类型可以让你暗示_任意类型_的值缺失并不需要一个特殊值。
来看一个例子。Swift 的`String`类型有一种构造器,作用是将一个`String`值转换成一个`Int`值。然而,并不是所有的字符串都可以转换成一个整数。字符串`"123"`可以被转换成数字`123`,但是字符串`"hello, world"`不行。
来看一个例子。Swift 的`Int`类型有一种构造器,作用是将一个`String`值转换成一个`Int`值。然而,并不是所有的字符串都可以转换成一个整数。字符串`"123"`可以被转换成数字`123`,但是字符串`"hello, world"`不行。
下面的例子使用这种构造器来尝试将一个`String`转换成`Int`
@ -638,7 +638,7 @@ if let actualNumber = Int(possibleNumber) {
“如果`Int(possibleNumber)`返回的可选`Int`包含一个值,创建一个叫做`actualNumber`的新常量并将可选包含的值赋给它。”
如果转换成功,`actualNumber`常量可以在`if`语句的第一个分支中使用。它已经被可选类型_包含的_值初始化过所以不需要再使用`!`后缀来获取它的值。在这个例子中,`actualNumber`只被用来输出转换结果。
如果转换成功,`actualNumber`常量可以在`if`语句的第一个分支中使用。它已经被可选类型 _包含的_ 值初始化过,所以不需要再使用`!`后缀来获取它的值。在这个例子中,`actualNumber`只被用来输出转换结果。
你可以在可选绑定中使用常量和变量。如果你想在`if`语句的第一个分支中操作`actualNumber`的值,你可以改成`if var actualNumber`,这样可选类型包含的值就会被赋给一个变量而非常量。
@ -782,11 +782,13 @@ assert(age >= 0)
当条件可能为假时使用断言但是最终一定要_保证_条件为真这样你的代码才能继续运行。断言的适用情景
* 整数类型的下标索引被传入一个自定义下标脚本实现,但是下标索引值可能太小或者太大。
* 整数类型的下标索引被传入一个自定义下标实现,但是下标索引值可能太小或者太大。
* 需要给函数传入一个值,但是非法的值可能导致函数不能正常执行。
* 一个可选值现在是`nil`,但是后面的代码运行需要一个非`nil`值。
请参考[下标脚本](./12_Subscripts.html)和[函数](./06_Functions.html)。
请参考[下标](./12_Subscripts.html)和[函数](./06_Functions.html)。
> 注意:
断言可能导致你的应用终止运行,所以你应当仔细设计你的代码来让非法条件不会出现。然而,在你的应用发布之前,有时候非法条件可能出现,这时使用断言可以快速发现问题。

View File

@ -6,46 +6,49 @@
> 校对:[EvilCome](https://github.com/Evilcome)
> 2.0
> 翻译+校对:[JackAlan](https://github.com/AlanMelody)
> 翻译+校对:[JackAlan](https://github.com/AlanMelody)
> 2.1
> 校对:[shanks](http://codebuild.me)
> 2.2
> 翻译+校对:[Cee](https://github.com/Cee)
本页包含内容:
- [术语](#terminology)
- [赋值运算符](#assignment_operator)
- [算术运算符](#arithmetic_operators)
- [组合赋值运算符Compound Assignment Operators](#compound_assignment_operators)
- [组合赋值运算符](#compound_assignment_operators)
- [比较运算符](#comparison_operators)
- [三目运算符Ternary Conditional Operator](#ternary_conditional_operator)
- [三目运算符](#ternary_conditional_operator)
- [空合运算符](#nil_coalescing_operator)
- [区间运算符](#range_operators)
- [逻辑运算符](#logical_operators)
运算符是检查、改变、合并值的特殊符号或短语。例如,加号`+`将两个数相加(如`let i = 1 + 2`)。更复杂的运算例子包括逻辑与运算符`&&`(如`if enteredDoorCode && passedRetinaScan`),或让 i 值加1的便捷自增运算符`++i`等。
运算符是检查、改变、合并值的特殊符号或短语。例如,加号`+`将两个数相加(如 `let i = 1 + 2`)。更复杂的运算例子包括逻辑与运算符 `&&`(如 `if enteredDoorCode && passedRetinaScan`),或让 i 值加 1 的便捷自增运算符 `++i` 等。
Swift 支持大部分标准 C 语言的运算符,且改进许多特性来减少常规编码错误。如:赋值符(`=`)不返回值,以防止把想要判断相等运算符(`==`)的地方写成赋值符导致的错误。算术运算符(`+``-``*``/``%`等)会检测并不允许值溢出,以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然允许你使用 Swift 的溢出运算符来实现溢出。详情参见[溢出运算符](../chapter2/25_Advanced_Operators.html#overflow_operators)。
区别于 C 语言,在 Swift 中你可以对浮点数进行取余运算(`%`Swift 还提供了 C 语言没有的表达两数之间的值的区间运算符(`a..<b``a...b`),这方便我们表达一个区间内的数值。
区别于 C 语言,在 Swift 中你可以对浮点数进行取余运算(`%`Swift 还提供了 C 语言没有的表达两数之间的值的区间运算符(`a..<b``a...b`),这方便我们表达一个区间内的数值。
本章节只描述了 Swift 中的基本运算符,[高级运算符](../chapter2/25_Advanced_Operators.html)包含了高级运算符,及如何自定义运算符,及如何进行自定义类型的运算符重载。
本章节只描述了 Swift 中的基本运算符,[高级运算符](../chapter2/25_Advanced_Operators.html)这章会包含 Swift 中的高级运算符,及如何自定义运算符,及如何进行自定义类型的运算符重载。
<a name="terminology"></a>
## 术语
运算符一元、二元和三元运算符。
运算符分为一元、二元和三元运算符。
- 一元运算符对单一操作对象操作(如`-a`)。一元运算符分前置运算符和后置运算符,前置运算符需紧跟在操作对象之前(如`!b`),后置运算符需紧跟在操作对象之后(如`i++`)。
- 二元运算符操作两个操作对象(如`2 + 3`),是中置的,因为它们出现在两个操作对象之间。
- 一元运算符对单一操作对象操作(如 `-a`)。一元运算符分前置运算符和后置运算符,前置运算符需紧跟在操作对象之前(如 `!b`),后置运算符需紧跟在操作对象之后(如 `i++`)。
- 二元运算符操作两个操作对象(如 `2 + 3`),是中置的,因为它们出现在两个操作对象之间。
- 三元运算符操作三个操作对象,和 C 语言一样Swift 只有一个三元运算符,就是三目运算符(`a ? b : c`)。
受运算符影响的值叫操作数,在表达式`1 + 2`中,加号`+`是二元运算符,它的两个操作数是值`1``2`
受运算符影响的值叫操作数,在表达式 `1 + 2` 中,加号 `+` 是二元运算符,它的两个操作数是值 `1``2`
<a name="assignment_operator"></a>
## 赋值运算符
赋值运算(`a = b`),表示用`b`的值来初始化或更新`a`的值:
赋值运算(`a = b`),表示用 `b` 的值来初始化或更新 `a` 的值:
```swift
let b = 10
@ -58,7 +61,7 @@ a = b
```swift
let (x, y) = (1, 2)
// 现在 x 等于 1, y 等于 2
// 现在 x 等于 1y 等于 2
```
与 C 语言和 Objective-C 不同Swift 的赋值操作并不返回任何值。所以以下代码是错误的:
@ -69,7 +72,7 @@ if x = y {
}
```
这个特性使你无法把(`==`)错写成(`=`),由于`if x = y`是错误代码Swift帮你避免此类错误的的发生。
这个特性使你无法把(`==`)错写成(`=`),由于 `if x = y` 是错误代码Swift帮你避免此类错误发生。
<a name="arithmetic_operators"></a>
## 算术运算符
@ -88,9 +91,9 @@ Swift 中所有数值类型都支持了基本的四则算术运算:
10.0 / 2.5 // 等于 4.0
```
与 C 语言和 Objective-C 不同的是Swift 默认情况下不允许在数值运算中出现溢出情况。但是你可以使用 Swift 的溢出运算符来实现溢出运算(如`a &+ b`)。详情参见[溢出运算符](../chapter2/25_Advanced_Operators.html#overflow_operators)。
与 C 语言和 Objective-C 不同的是Swift 默认情况下不允许在数值运算中出现溢出情况。但是你可以使用 Swift 的溢出运算符来实现溢出运算(如 `a &+ b`)。详情参见[溢出运算符](../chapter2/25_Advanced_Operators.html#overflow_operators)。
加法运算符也可用于`String`的拼接:
加法运算符也可用于 `String` 的拼接:
```swift
"hello, " + "world" // 等于 "hello, world"
@ -98,16 +101,16 @@ Swift 中所有数值类型都支持了基本的四则算术运算:
### 求余运算符
求余运算(`a % b`)是计算`b`的多少倍刚刚好可以容入`a`,返回多出来的那部分(余数)。
求余运算(`a % b`)是计算 `b` 的多少倍刚刚好可以容入`a`,返回多出来的那部分(余数)。
>注意:
求余运算(`%`)在其他语言也叫取模运算。然而严格说来,我们看该运算符对负数的操作结果,"求余"比"取模"更合适些。
> 注意:
求余运算(`%`)在其他语言也叫取模运算。然而严格说来,我们看该运算符对负数的操作结果,求余」比「取模更合适些。
我们来谈谈取余是怎么回事,计算`9 % 4`,你先计算出`4`的多少倍会刚好可以容入`9`中:
我们来谈谈取余是怎么回事,计算 `9 % 4`,你先计算出 `4` 的多少倍会刚好可以容入 `9` 中:
![Art/remainderInteger_2x.png](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/remainderInteger_2x.png "Art/remainderInteger_2x.png")
2倍非常好那余数是1用橙色标出
你可以在 `9` 中放入两个 `4`,那余数是 1用橙色标出
在 Swift 中可以表达为:
@ -115,13 +118,13 @@ Swift 中所有数值类型都支持了基本的四则算术运算:
9 % 4 // 等于 1
```
为了得到`a % b`的结果,`%`计算了以下等式,并输出`余数`作为结果:
为了得到 `a % b` 的结果,`%` 计算了以下等式,并输出`余数`作为结果:
a = (b × 倍数) + 余数
`倍数`取最大值的时候,就会刚好可以容入`a`中。
`倍数`取最大值的时候,就会刚好可以容入 `a` 中。
`9``4`代入等式中,我们得`1`
`9``4` 代入等式中,我们得 `1`
9 = (4 × 2) + 1
@ -131,13 +134,13 @@ Swift 中所有数值类型都支持了基本的四则算术运算:
-9 % 4 // 等于 -1
```
`-9``4`代入等式,`-2`是取到的最大整数:
`-9``4` 代入等式,`-2` 是取到的最大整数:
-9 = (4 × -2) + -1
余数是`-1`
余数是 `-1`
在对负数`b`求余时,`b`的符号会被忽略。这意味着 `a % b``a % -b`的结果是相同的。
在对负数 `b` 求余时,`b` 的符号会被忽略。这意味着 `a % b``a % -b` 的结果是相同的。
### 浮点数求余计算
@ -147,27 +150,27 @@ Swift 中所有数值类型都支持了基本的四则算术运算:
8 % 2.5 // 等于 0.5
```
这个例子中,`8`除于`2.5`等于`3``0.5`,所以结果是一个`Double``0.5`
这个例子中,`8` 除以 `2.5` 等于 `3``0.5`,所以结果是一个 `Double` 型的值为 `0.5`
![Art/remainderFloat_2x.png](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/remainderFloat_2x.png "Art/remainderFloat_2x.png")
### 自增和自减运算
和 C 语言一样Swift 也提供了对变量本身加1或减1的自增(`++`)和自减(`--`)的缩略算符。其操作对象可以是整形和浮点型。
和 C 语言一样Swift 也提供了对变量本身加 1 或减 1 的自增(`++`)和自减(`--`)的缩略算符。其操作对象可以是整形和浮点型。
```swift
var i = 0
++i // 现在 i = 1
```
每调用一次`++i``i`的值就会加1。实际上`++i``i = i + 1`的简写,而`--i``i = i - 1`的简写。
每调用一次 `++i``i` 的值就会加 1。实际上`++i``i = i + 1` 的简写,而 `--i``i = i - 1` 的简写。
`++``--`既可以用作前置运算又可以用作后置运算。`++i``i++``--i``i--`都是有效的写法
`++``--` 既可以用作前置运算又可以用作后置运算。`++i``i++` 都是有效的自增的写法;相类似对应自减的写法则是 `--i``i--`
我们需要注意的是这些运算符即可修改了`i`的值也可以返回`i`的值。如果你只想修改`i`的值,那你就可以忽略这个返回值。但如果你想使用返回值,你就需要留意前置和后置操作的返回值是不同的,们遵循以下原则:
我们需要注意的是这些运算符即可修改了 `i` 的值也可以返回 `i` 的值。如果你只想修改 `i` 的值,那你就可以忽略这个返回值。但如果你想使用返回值,你就需要留意前置和后置操作的返回值是不同的,们遵循以下原则:
-`++`前置的时候,先自増再返回。
-`++`后置的时候,先返回再自增。
- `++` 前置的时候,先自増再返回。
- `++` 后置的时候,先返回再自增。
例如:
@ -177,16 +180,16 @@ let b = ++a // a 和 b 现在都是 1
let c = a++ // a 现在 2, 但 c 是 a 自增前的值 1
```
上述例子,`let b = ++a`先把`a`加1了再返回`a`的值。所以`a``b`都是新值`1`
上述例子,`let b = ++a` 先把 `a` 加 1 了再返回 `a` 的值。所以 `a``b` 都是新值 `1`
`let c = a++`,是先返回了`a`的值,然后`a`才加1。所以`c`得到了`a`的旧值1`a`加1后变成2。
`let c = a++`,是先返回了 `a` 的值,然后 `a` 才加 1。所以 `c` 得到了 `a` 的旧值 1 `a` 加 1 后变成 2。
除非你需要使用`i++`的特性,不然推荐你使用`++i``--i`,因为先修改后返回这样的行为更符合我们的逻辑。
除非你需要使用 `i++` 的特性,不然推荐你使用 `++i``--i`,因为先修改后返回这样的行为更符合我们的逻辑。
### 一元负号运算符
数值的正负号可以使用前缀`-`(即一元负号)来切换:
数值的正负号可以使用前缀 `-`(即一元负号)来切换:
```swift
let three = 3
@ -205,28 +208,29 @@ let minusSix = -6
let alsoMinusSix = +minusSix // alsoMinusSix 等于 -6
```
虽然一元`+`什么都不会改变,但当你在使用一元负号来表达负数时,你可以使用一元正号来表达正数,如此你的代码会具有对称美。
虽然一元 `+` 什么都不会改变,但当你在使用一元负号来表达负数时,你可以使用一元正号来表达正数,如此你的代码会具有对称美。
<a name="compound_assignment_operators"></a>
## 组合赋值运算符Compound Assignment Operators
## 组合赋值运算符
如同 C 语言Swift 也提供把其他运算符和赋值运算(`=`)组合的组合赋值运算符,组合加运算(`+=`)是其中一个例子:
```swift
var a = 1
a += 2 // a 现在是 3
a += 2
// a 现在是 3
```
表达式`a += 2``a = a + 2`的简写,一个组合加运算就是把加法运算和赋值运算组合成进一个运算符里,同时完成两个运算任务。
表达式 `a += 2``a = a + 2` 的简写,一个组合加运算就是把加法运算和赋值运算组合成进一个运算符里,同时完成两个运算任务。
>注意:
> 注意:
复合赋值运算没有返回值,`let b = a += 2`这类代码是错误。这不同于上面提到的自增和自减运算符。
在[表达式](../chapter3/04_Expressions.html)章节里有复合运算符的完整列表。
<a name="comparison_operators"></a>
## 比较运算符
## 比较运算符Comparison Operators
所有标准 C 语言中的比较运算都可以在 Swift 中使用:
@ -238,7 +242,7 @@ a += 2 // a 现在是 3
- 小于等于(`a <= b`
> 注意:
Swift 也提供恒等`===`和不恒等`!==`这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在[类与结构](../chapter2/09_Classes_and_Structures.html)。
Swift 也提供恒等`===`和不恒等`!==`这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在[类与结构](../chapter2/09_Classes_and_Structures.html)。
每个比较运算都返回了一个标识表达式是否成立的布尔值:
@ -263,12 +267,25 @@ if name == "world" {
// 输出 "hello, world", 因为 `name` 就是等于 "world"
```
关于`if`语句,请看[控制流](../chapter2/05_Control_Flow.html)。
关于 `if` 语句,请看[控制流](../chapter2/05_Control_Flow.html)。
当元组中的值可以比较时,你也可以使用这些运算符来比较它们的大小。例如,因为 `Int``String` 类型的值可以比较,所以类型为 `(Int, String)` 的元组也可以被比较。相反,`Bool` 不能被比较,也意味着存有布尔类型的元组不能被比较。
比较元组大小会按照从左到右、逐值比较的方式,直到发现有两个值不等时停止。如果所有的值都相等,那么这一对元组我们就称它们是相等的。例如:
```swift
(1, "zebra") < (2, "apple") // true因为 1 小于 2
(3, "apple") < (3, "bird") // true因为 3 等于 3但是 apple 小于 bird
(4, "dog") == (4, "dog") // true因为 4 等于 4dog 等于 dog
```
> 注意:
Swift 标准库只能比较七个以内元素的元组比较函数。如果你的元组元素超过七个时,你需要自己实现比较运算符。
<a name="ternary_conditional_operator"></a>
## 三目运算符(Ternary Conditional Operator)
## 三目运算符Ternary Conditional Operator
三目运算符的特殊在于它是有三个操作数的运算符,它的原型`问题 ? 答案1 : 答案2`。它简洁地表达根据`问题`成立与否作出二选一的操作。如果`问题`成立,返回`答案1`的结果; 如果不成立,返回`答案2`的结果。
三目运算符的特殊在于它是有三个操作数的运算符,它的形式`问题 ? 答案 1 : 答案 2`。它简洁地表达根据 `问题`成立与否作出二选一的操作。如果 `问题` 成立,返回 `答案 1` 的结果;反之返回 `答案 2` 的结果。
三目运算符是以下代码的缩写形式:
@ -280,7 +297,7 @@ if question {
}
```
这里有个计算表格行高的例子。如果有表头那行高应比内容高度要高出50点如果没有表头只需高出20点
这里有个计算表格行高的例子。如果有表头,那行高应比内容高度要高出 50 点;如果没有表头,只需高出 20 点:
```swift
let contentHeight = 40
@ -303,28 +320,25 @@ if hasHeader {
// rowHeight 现在是 90
```
第一段代码例子使用了三目运算,所以一行代码就能让我们得到正确答案。这比第二段代码简洁得多,无需将`rowHeight`定义成变量,因为它的值无需在`if`语句中改变。
第一段代码例子使用了三目运算,所以一行代码就能让我们得到正确答案。这比第二段代码简洁得多,无需将 `rowHeight` 定义成变量,因为它的值无需在 `if` 语句中改变。
三目运算提供有效率且便捷的方式来表达二选一的选择。需要注意的事,过度使用三目运算符会使简洁的代码变的难懂。我们应避免在一个组合语句中使用多个三目运算符。
<a name="nil_coalescing_operator"></a>
## 空合运算符(Nil Coalescing Operator)
## 空合运算符Nil Coalescing Operator
空合运算符(`a ?? b`)将对可选类型`a`进行空判断,如果`a`包含一个值就进行解封,否则就返回一个默认值`b`.这个运算符有两个条件:
空合运算符`a ?? b`将对可选类型 `a` 进行空判断,如果 `a` 包含一个值就进行解封,否则就返回一个默认值 `b`。表达式 `a` 必须是 Optional 类型。默认值 `b` 的类型必须要和 `a` 存储值的类型保持一致。
- 表达式`a`必须是Optional类型
- 默认值`b`的类型必须要和`a`存储值的类型保持一致
空合运算符是对以下代码的简短表达方法
空合运算符是对以下代码的简短表达方法:
```swift
a != nil ? a! : b
```
上述代码使用了三目运算符。当可选类型`a`的值不为空时,进行强制解封(`a!`)访问`a`中值,反之当`a`中值为空时返回默认值b。无疑空合运算符(`??`)提供了一种更为优雅的方式去封装条件判断和解封两种行为,显得简洁以及更具可读性。
上述代码使用了三目运算符。当可选类型 `a` 的值不为空时,进行强制解封`a!`访问 `a` 中的值;反之返回默认值 `b`。无疑空合运算符`??`提供了一种更为优雅的方式去封装条件判断和解封两种行为,显得简洁以及更具可读性。
> 注意:
如果`a`为非空值(`non-nil`),那么值`b`将不会被估值。这也就是所谓的短路求值。
如果 `a` 为非空值`non-nil`那么值 `b` 将不会被计算。这也就是所谓的短路求值。
下文例子采用空合运算符,实现了在默认颜色名和可选自定义颜色名之间抉择:
@ -336,10 +350,10 @@ var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 的值为空,所以 colorNameToUse 的值为 "red"
```
`userDefinedColorName`变量被定义为一个可选`String`类型,默认值为`nil`。由于`userDefinedColorName`是一个可选类型,我们可以使用空合运算符去判断其值。在上一个例子中,通过空合运算符为一个名为`colorNameToUse`的变量赋予一个字符串类型初始值。
由于`userDefinedColorName`值为空,因此表达式`userDefinedColorName ?? defaultColorName`返回`defaultColorName`的值,即`red`
`userDefinedColorName` 变量被定义为一个可选`String` 类型,默认值为 `nil`。由于 `userDefinedColorName` 是一个可选类型,我们可以使用空合运算符去判断其值。在上一个例子中,通过空合运算符为一个名为 `colorNameToUse` 的变量赋予一个字符串类型初始值。
由于 `userDefinedColorName` 值为空,因此表达式 `userDefinedColorName ?? defaultColorName` 返回 `defaultColorName` 的值,即 `red`
另一种情况,分配一个非空值(`non-nil`)给`userDefinedColorName`,再次执行空合运算,运算结果为封包在`userDefaultColorName`中的值,而非默认值。
另一种情况,分配一个非空值`non-nil`)给 `userDefinedColorName`,再次执行空合运算,运算结果为封包在 `userDefaultColorName` 中的值,而非默认值。
```swift
userDefinedColorName = "green"
@ -348,14 +362,14 @@ colorNameToUse = userDefinedColorName ?? defaultColorName
```
<a name="range_operators"></a>
## 区间运算符
## 区间运算符Range Operators
Swift 提供了两个方便表达一个区间的值的运算符。
### 闭区间运算符
闭区间运算符(`a...b`)定义一个包含从`a``b`(包括`a``b`)的所有值的区间`b`必须大于等于`a`
闭区间运算符(`a...b`)定义一个包含从 `a``b`包括 `a``b`的所有值的区间`a` 的值不能超过 `b`
闭区间运算符在迭代一个区间的所有值时是非常有用的,如在`for-in`循环中:
闭区间运算符在迭代一个区间的所有值时是非常有用的,如在 `for-in` 循环中:
```swift
for index in 1...5 {
@ -368,14 +382,14 @@ for index in 1...5 {
// 5 * 5 = 25
```
关于`for-in`,请看[控制流](../chapter2/05_Control_Flow.html)。
关于 `for-in`,请看[控制流](../chapter2/05_Control_Flow.html)。
### 半开区间运算符
半开区间(`a..<b`)定义一个从`a``b`但不包括`b`的区间。
半开区间(`a..<b`)定义一个从 `a``b` 但不包括 `b` 的区间。
之所以称为半开区间,是因为该区间包含第一个值而不包括最后的值。
半开区间的实用性在于当你使用一个从0开始的列表(如数组)非常方便地从0数到列表的长度。
半开区间的实用性在于当你使用一个从 0 开始的列表如数组非常方便地从0数到列表的长度。
```swift
let names = ["Anna", "Alex", "Brian", "Jack"]
@ -389,10 +403,10 @@ for i in 0..<count {
// 第 4 个人叫 Jack
```
数组有4个元素,但`0..<count`只数到3(最后一个元素的下标),因为它是半开区间。关于数组,请查阅[数组](../chapter2/04_Collection_Types.html#arrays)。
数组有 4 个元素,但 `0..<count` 只数到3最后一个元素的下标,因为它是半开区间。关于数组,请查阅[数组](../chapter2/04_Collection_Types.html#arrays)。
<a name="logical_operators"></a>
## 逻辑运算
## 逻辑运算Logical Operators
逻辑运算的操作对象是逻辑布尔值。Swift 支持基于 C 语言的三个标准逻辑运算。
@ -402,9 +416,9 @@ for i in 0..<count {
### 逻辑非
逻辑非运算(`!a`)对一个布尔值取反,使得`true``false``false``true`
逻辑非运算(`!a`)对一个布尔值取反,使得 `true``false``false``true`
它是一个前置运算符,需紧跟在操作数之前,且不加空格。读作`非 a`,例子如下:
它是一个前置运算符,需紧跟在操作数之前,且不加空格。读作 `非 a` ,例子如下:
```swift
let allowedEntry = false
@ -414,17 +428,17 @@ if !allowedEntry {
// 输出 "ACCESS DENIED"
```
`if !allowedEntry`语句可以读作如果非 allowedEntry。”,接下一行代码只有在非 allowedEntry”为`true`,即`allowEntry``false`时被执行。
`if !allowedEntry` 语句可以读作如果非 allowedEntry,接下一行代码只有在非 allowedEntry」为 `true`,即 `allowEntry``false` 时被执行。
在示例代码中,小心地选择布尔常量或变量有助于代码的可读性,并且避免使用双重逻辑非运算,或混乱的逻辑语句。
### 逻辑与
逻辑与(`a && b`)表达了只有`a``b`的值都为`true`时,整个表达式的值才会是`true`
逻辑与(`a && b`)表达了只有 `a``b` 的值都为 `true` 时,整个表达式的值才会是 `true`
只要任意一个值为`false`,整个表达式的值就为`false`。事实上,如果第一个值为`false`,那么是不去计算第二个值的,因为它已经不可能影响整个表达式的结果了。这被称做短路计算short-circuit evaluation
只要任意一个值为 `false`,整个表达式的值就为 `false`。事实上,如果第一个值为 `false`,那么是不去计算第二个值的,因为它已经不可能影响整个表达式的结果了。这被称做短路计算short-circuit evaluation
以下例子,只有两个`Bool`值都为`true`的时候才允许进入:
以下例子,只有两个 `Bool` 值都为 `true` 的时候才允许进入 if
```swift
let enteredDoorCode = true
@ -439,11 +453,11 @@ if enteredDoorCode && passedRetinaScan {
### 逻辑或
逻辑或(`a || b`)是一个由两个连续的`|`组成的中置运算符。它表示了两个逻辑表达式的其中一个为`true`,整个表达式就为`true`
逻辑或(`a || b`)是一个由两个连续的 `|` 组成的中置运算符。它表示了两个逻辑表达式的其中一个为 `true`,整个表达式就为 `true`
同逻辑与运算类似,逻辑或也是短路计算的,当左端的表达式为`true`时,将不计算右边的表达式了,因为它不可能改变整个表达式的值了。
同逻辑与运算类似,逻辑或也是短路计算的,当左端的表达式为 `true` 时,将不计算右边的表达式了,因为它不可能改变整个表达式的值了。
以下示例代码中,第一个布尔值(`hasDoorKey`)为`false`,但第二个值(`knowsOverridePassword`)为`true`,所以整个表达是`true`,于是允许进入:
以下示例代码中,第一个布尔值(`hasDoorKey`)为 `false`,但第二个值(`knowsOverridePassword`)为 `true`,所以整个表达是 `true`,于是允许进入:
```swift
let hasDoorKey = false
@ -469,14 +483,14 @@ if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
// 输出 "Welcome!"
```
这个例子使用了含多个`&&``||`的复合逻辑。但无论怎样,`&&``||`始终只能操作两个值。所以这实际是三个简单逻辑连续操作的结果。我们来解读一下:
这个例子使用了含多个 `&&``||` 的复合逻辑。但无论怎样,`&&``||` 始终只能操作两个值。所以这实际是三个简单逻辑连续操作的结果。我们来解读一下:
如果我们输入了正确的密码并通过了视网膜扫描,或者我们有一把有效的钥匙,又或者我们知道紧急情况下重置的密码,我们就能把门打开进入。
前两种情况,我们都不满足,所以前两个简单逻辑的结果是`false`,但是我们是知道紧急情况下重置的密码的,所以整个复杂表达式的值还是`true`
前两种情况,我们都不满足,所以前两个简单逻辑的结果是 `false`,但是我们是知道紧急情况下重置的密码的,所以整个复杂表达式的值还是 `true`
>注意:
Swift 逻辑操作符`&&``||`是左结合的,这意味着拥有多元逻辑操作符的复合表达式优先计算最左边的子表达式。
> 注意:
Swift 逻辑操作符 `&&``||` 是左结合的,这意味着拥有多元逻辑操作符的复合表达式优先计算最左边的子表达式。
### 使用括号来明确优先级

View File

@ -10,7 +10,7 @@
> 2.1
> 翻译:[DianQK](https://github.com/DianQK)
> 校对:[shanks](http://codebuild.me)
> 校对:[shanks](http://codebuild.me), [Realank](https://github.com/Realank)
本页包含内容:
@ -29,7 +29,7 @@
`String`是例如"hello, world""albatross"这样的有序的`Character`(字符)类型的值的集合。通过`String`类型来表示。
一个`String`的内容可以用变量的方式读取,它包括一个`Character`值的集合。
一个`String`的内容可以用许多方式读取,它包括一个`Character`值的集合。
创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。
字符串连接操作只需要简单地通过`+`符号将两个字符串相连即可。与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。你也可以在字符串内插过程中使用字符串插入常量、变量、字面量表达成更长的字符串,这样可以很容易的创建自定义的字符串值,进行展示、存储以及打印。
尽管语法简易,但`String`类型是一种快速、现代化的字符串实现。
@ -68,7 +68,7 @@ var anotherEmptyString = String() // 初始化方法
// 两个字符串均为空并等价。
```
您可以通过检查其`Boolean`类型的`isEmpty`属性来判断该字符串是否为空:
您可以通过检查其`Bool`类型的`isEmpty`属性来判断该字符串是否为空:
```swift
if emptyString.isEmpty {
@ -248,7 +248,7 @@ let sparklingHeart = "\u{1F496}" // 💖, Unicode 标量 U+1F496
```swift
let eAcute: Character = "\u{E9}" // é
let combinedEAcute: Character = "\u{65}\u{301}" // e 后面加上 ́
// eAcute 是 é, combinedEAcute 是
// eAcute 是 é, combinedEAcute 是 é
```
可扩展的字符群集是一个灵活的方法,用许多复杂的脚本字符表示单一的`Character`值。
@ -259,7 +259,7 @@ let combinedEAcute: Character = "\u{65}\u{301}" // e 后面加上 ́
```swift
let precomposed: Character = "\u{D55C}" // 한
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
// precomposed 是 한, decomposed 是 한
// precomposed 是 한, decomposed 是
```
可拓展的字符群集可以使包围记号(例如`COMBINING ENCLOSING CIRCLE`或者`U+20DD`)的标量包围其他 Unicode 标量,作为一个单一的`Character`值:
@ -269,7 +269,7 @@ let enclosedEAcute: Character = "\u{E9}\u{20DD}"
// enclosedEAcute 是 é⃝
```
局部的指示符号的 Unicode 标量可以组合成一个单一的`Character`值,例如`REGIONAL INDICATOR SYMBOL LETTER U`(`U+1F1FA`)和`REGIONAL INDICATOR SYMBOL LETTER S`(`U+1F1F8`)
地域性指示符号的 Unicode 标量可以组合成一个单一的`Character`值,例如`REGIONAL INDICATOR SYMBOL LETTER U`(`U+1F1FA`)和`REGIONAL INDICATOR SYMBOL LETTER S`(`U+1F1F8`)
```swift
@ -290,7 +290,7 @@ print("unusualMenagerie has \(unusualMenagerie.characters.count) characters")
注意在 Swift 中,使用可拓展的字符群集作为`Character`值来连接或改变字符串时,并不一定会更改字符串的字符数量。
例如,如果你用四个字符的单词`cafe`初始化一个新的字符串,然后添加一个`COMBINING ACTUE ACCENT`(`U+0301`)作为字符串的结尾。最终这个字符串的字符数量仍然是`4`,因为第四个字符是``,而不是`e`
例如,如果你用四个字符的单词`cafe`初始化一个新的字符串,然后添加一个`COMBINING ACTUE ACCENT`(`U+0301`)作为字符串的结尾。最终这个字符串的字符数量仍然是`4`,因为第四个字符是`é`,而不是`e`
```swift
var word = "cafe"
@ -312,7 +312,7 @@ print("the number of characters in \(word) is \(word.characters.count)")
<a name="accessing_and_modifying_a_string"></a>
## 访问和修改字符串 (Accessing and Modifying a String)
你可以通字符串的属性和方法来访问和读取它,当然也可以用下标语法完成。
你可以通字符串的属性和方法来访问和修改它,当然也可以用下标语法完成。
<a name="string_indices"></a>
### 字符串索引 (String Indices)
@ -351,9 +351,9 @@ greeting.endIndex.successor() // error
```swift
for index in greeting.characters.indices {
print("\(greeting[index]) ", terminator: " ")
print("\(greeting[index]) ", terminator: "")
}
// 打印输出 "G u t e n T a g !"
// 打印输出 "G u t e n T a g ! "
```
<a name="inserting_and_removing"></a>
@ -417,7 +417,7 @@ if quotation == sameQuotation {
// "Voulez-vous un café?" 使用 LATIN SMALL LETTER E WITH ACUTE
let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"
// "Voulez-vous un caf?" 使用 LATIN SMALL LETTER E and COMBINING ACUTE ACCENT
// "Voulez-vous un café?" 使用 LATIN SMALL LETTER E and COMBINING ACUTE ACCENT
let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"
if eAcuteQuestion == combinedEAcuteQuestion {
@ -440,7 +440,7 @@ if latinCapitalLetterA != cyrillicCapitalLetterA {
```
> 注意:
> 在 Swift 中,字符串和字符并不区分区域
> 在 Swift 中,字符串和字符并不区分地域(not locale-sensitive)
<a name="prefix_and_suffix_equality"></a>
@ -502,7 +502,7 @@ print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
<a name="unicode_representations_of_strings"></a>
## 字符串的 Unicode 表示形式Unicode Representations of Strings
当一个 Unicode 字符串被写进文本文件或者其他储存时,字符串中的 Unicode 标量会用 Unicode 定义的几种编码格式编码。每一个字符串中的小块编码都被称代码单元。这些包括 UTF-8 编码格式编码字符串为8位的代码单元 UTF-16 编码格式编码字符串位16位的代码单元以及 UTF-32 编码格式编码字符串32位的代码单元
当一个 Unicode 字符串被写进文本文件或者其他储存时,字符串中的 Unicode 标量会用 Unicode 定义的几种`编码格式`encoding forms编码。每一个字符串中的小块编码都被称`代码单元`code units。这些包括 UTF-8 编码格式编码字符串为8位的代码单元 UTF-16 编码格式编码字符串位16位的代码单元以及 UTF-32 编码格式编码字符串32位的代码单元
Swift 提供了几种不同的方式来访问字符串的 Unicode 表示形式。
您可以利用`for-in`来对字符串进行遍历,从而以 Unicode 可扩展的字符群集的方式访问每一个`Character`值。
@ -514,7 +514,7 @@ Swift 提供了几种不同的方式来访问字符串的 Unicode 表示形式
* UTF-16 代码单元集合 (利用字符串的`utf16`属性进行访问)
* 21位的 Unicode 标量值集合,也就是字符串的 UTF-32 编码格式 (利用字符串的`unicodeScalars`属性进行访问)
下面由`D``o``g``‼`(`DOUBLE EXCLAMATION MARK`, Unicode 标量 `U+203C`)和`<EFBFBD>`(`DOG FACE`Unicode 标量为`U+1F436`)组成的字符串中的每一个字符代表着一种不同的表示:
下面由`D`,`o`,`g`,`‼`(`DOUBLE EXCLAMATION MARK`, Unicode 标量 `U+203C`)和`🐶`(`DOG FACE`Unicode 标量为`U+1F436`)组成的字符串中的每一个字符代表着一种不同的表示:
```swift
let dogString = "Dog‼🐶"
@ -633,7 +633,7 @@ print("")
### Unicode 标量表示 (Unicode Scalars Representation)
您可以通过遍历`String`值的`unicodeScalars`属性来访问它的 Unicode 标量表示。
其为`UnicodeScalarView`类型的属性,`UnicodeScalarView``UnicodeScalar`的集合。
其为`UnicodeScalarView`类型的属性,`UnicodeScalarView``UnicodeScalar`类型的值的集合。
`UnicodeScalar`是21位的 Unicode 代码点。
每一个`UnicodeScalar`拥有一个`value`属性可以返回对应的21位数值`UInt32`来表示:
@ -649,7 +649,7 @@ print("")
<td>🐶<br>U+1F436</td>
</tr>
<tr height="77">
<td height="77">UTF-16<br>Code Unit</td>
<td height="77">Unicode Scalar<br>Code Unit</td>
<td>68</td>
<td>111</td>
<td>103</td>

View File

@ -223,7 +223,7 @@ firstItem = shoppingList[0]
```swift
let apples = shoppingList.removeLast()
// 数组的最后一项被移除了
// shoppingList 现在只有5项不包括 cheese
// shoppingList 现在只有5项不包括 Apples
// apples 常量的值现在等于 "Apples" 字符串
```
@ -460,7 +460,7 @@ oddDigits.exclusiveOr(singleDigitPrimeNumbers).sort()
* 使用`isSubsetOf(_:)`方法来判断一个集合中的值是否也被包含在另外一个集合中。
* 使用`isSupersetOf(_:)`方法来判断一个集合中包含另一个集合中所有的值。
* 使用`isStrictSubsetOf(_:)`或者`isStrictSupersetOf(_:)`方法来判断一个集合是否是另外一个集合的子集合或者父集合并且两个集合并不相等。
* 使用`isDisjointWith(_:)`方法来判断两个集合是否不含有相同的值。
* 使用`isDisjointWith(_:)`方法来判断两个集合是否不含有相同的值(是否没有交集)
```swift
let houseAnimals: Set = ["🐶", "🐱"]

View File

@ -12,31 +12,27 @@
> 翻译:[Prayer](https://github.com/futantan)
> 校对:[shanks](http://codebuild.me)
> 2.2
> 翻译:[LinusLing](https://github.com/linusling)
> 校对:[]()
本页包含内容:
- [For 循环](#for_loops)
- [For-In 循环](#for_in_loops)
- [While 循环](#while_loops)
- [条件语句](#conditional_statement)
- [控制转移语句Control Transfer Statements](#control_transfer_statements)
- [提前退出](#early_exit)
- [检测API可用性](#checking_api_availability)
- [检测 API 可用性](#checking_api_availability)
Swift 提供了类似 C 语言的流程控制结构,包括可以多次执行任务的`for``while`循环,基于特定条件选择执行不同代码分支的`if``guard``switch`语句,还有控制流程跳转到其他代码的`break``continue`语句。
Swift提供了多种流程控制结构,包括可以多次执行任务的`while`循环,基于特定条件选择执行不同代码分支的`if``guard``switch`语句,还有控制流程跳转到其他代码的`break``continue`语句。
除了 C 语言里面传统的 for 循环,Swift 还增加了`for-in`循环用来更简单地遍历数组array字典dictionary区间range字符串string和其他序列类型。
Swift 还增加了`for-in`循环用来更简单地遍历数组array字典dictionary区间range字符串string和其他序列类型。
Swift 的`switch`语句比 C 语言中更加强大。在 C 语言中,如果某个 case 不小心漏写了`break`,这个 case 就会贯穿至下一个 caseSwift 无需写`break`所以不会发生这种贯穿的情况。case 还可以匹配更多的类型模式包括区间匹配range matching元组tuple和特定类型的描述。`switch`的 case 语句中匹配的值可以是由 case 体内部临时的常量或者变量决定,也可以由`where`分句描述更复杂的匹配条件。
<a name="for_loops"></a>
## For 循环
Swift 提供两种`for`循环形式以来按照指定的次数多次执行一系列语句:
* `for-in`循环对一个集合里面的每个元素执行一系列语句。
* for 循环,用来重复执行一系列语句直到达成特定条件达成,一般通过在每次循环完成后增加计数器的值来实现。
<a name="for_in"></a>
### For-In
<a name="for_in_loops"></a>
## For-In 循环
你可以使用`for-in`循环来遍历一个集合里面的所有元素,例如由数字表示的区间、数组中的元素、字符串中的字符。
@ -99,53 +95,6 @@ for (animalName, legCount) in numberOfLegs {
字典元素的遍历顺序和插入顺序可能不同,字典的内容在内部是无序的,所以遍历元素时不能保证顺序。关于数组和字典,详情参见[集合类型](./04_Collection_Types.html)。
<a name="for"></a>
### For
除了`for-in`循环Swift 提供使用条件判断和递增方法的标准 C 样式`for`循环:
```swift
for var index = 0; index < 3; ++index {
print("index is \(index)")
}
// index is 0
// index is 1
// index is 2
```
下面是一般情况下这种循环方式的格式:
```swift
for initialization; condition; increment {
statements
}
```
和 C 语言中一样,分号将循环的定义分为 3 个部分不同的是Swift 不需要使用圆括号将“initialization; condition; increment”包括起来。
这个循环执行流程如下:
1. 循环首次启动时,*初始化表达式( initialization expression *被调用一次,用来初始化循环所需的所有常量和变量。
2. *条件表达式condition expression*被调用,如果表达式调用结果为`false`,循环结束,继续执行`for`循环关闭大括号(`}`)之后的代码。如果表达式调用结果为`true`,则会执行大括号内部的代码。
3. 执行所有语句之后,执行*递增表达式increment expression*。通常会增加或减少计数器的值,或者根据语句输出来修改某一个初始化的变量。当递增表达式运行完成后,重复执行第 2 步,条件表达式会再次执行。
在初始化表达式中声明的常量和变量(比如`var index = 0`)只在`for`循环的生命周期里有效。如果想在循环结束后访问`index`的值,你必须要在循环生命周期开始前声明`index`
```swift
var index: Int
for index = 0; index < 3; ++index {
print("index is \(index)")
}
// index is 0
// index is 1
// index is 2
print("The loop statements were executed \(index) times")
// 输出 "The loop statements were executed 3 times
```
注意`index`在循环结束后最终的值是`3`而不是`2`。最后一次调用递增表达式`++index`会将`index`设置为`3`,从而导致`index < 3`条件为`false`,并终止循环。
<a name="while_loops"></a>
## While 循环
@ -169,7 +118,7 @@ while condition {
下面的例子来玩一个叫做蛇和梯子的小游戏,也叫做滑道和梯子:
![image](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/snakesAndLadders_2x.png)
![image](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/snakesAndLadders_2x.png)
游戏的规则如下:
@ -212,11 +161,12 @@ while square < finalSquare {
print("Game over!")
```
本例中使用了最简单的方法来模拟掷骰子。 `diceRoll`的值并不是一个随机数,而是以`0`为初始值,之后每一次`while`循环,`diceRoll`的值使用前置自增操作符(`++i`)来自增 1 ,然后检测是否超出了最大值。`++diceRoll`调用完成_后_返回值等于`diceRoll`自增后的值。任何时候如果`diceRoll`的值等于7时,就超过了骰子的最大值,会被重置为`1`。所以`diceRoll`的取值顺序会一直是`1``2``3``4``5``6``1``2`
本例中使用了最简单的方法来模拟掷骰子。 `diceRoll`的值并不是一个随机数,而是以`0`为初始值,之后每一次`while`循环,`diceRoll`的值使用前置自增操作符(`++i`)来自增 1 ,然后检测是否超出了最大值。任何时候如果`diceRoll`的值等于 7 时,就超过了骰子的最大值,会被重置为`1`。所以`diceRoll`的取值顺序会一直是`1`。因此,`diceRoll` 所有的值只可能是 `1` `2``3``4``5``6``1``2`
掷完骰子后,玩家向前移动`diceRoll`个方格,如果玩家移动超过了第 25 个方格,这个时候游戏结束,相应地,代码会在`square`增加`board[square]`的值向前或向后移动(遇到了梯子或者蛇)之前,检测`square`的值是否小于`board``count`属性。
如果没有这个检测(`square < board.count``board[square]`可能会越界访问`board`数组,导致错误。例如如果`square`等于`26` 代码会去尝试访问`board[26]`,超过数组的长度。
> 注意:
> 如果没有这个检测(`square < board.count``board[square]`可能会越界访问`board`数组,导致错误。例如如果`square`等于`26` 代码会去尝试访问`board[26]`,超过数组的长度。
当本轮`while`循环运行完毕,会再检测循环条件是否需要再运行一次循环。如果玩家移动到或者超过第 25 个方格,循环条件结果为`false`,此时游戏结束。
@ -325,7 +275,7 @@ if temperatureInFahrenheit <= 32 {
实际上,最后的`else`语句是可选的:
```swift
temperatureInFahrenheit = 72
temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
@ -346,7 +296,8 @@ if temperatureInFahrenheit <= 32 {
switch some value to consider {
case value 1:
respond to value 1
case value 2, value 3:
case value 2,
value 3:
respond to value 2 or 3
default:
otherwise, do something else
@ -407,7 +358,8 @@ default:
```swift
switch some value to consider {
case value 1, value 2:
case value 1,
value 2:
statements
}
```
@ -442,7 +394,7 @@ print("There are \(naturalCount) \(countedThings).")
// 输出 "There are dozens of moons orbiting Saturn."
```
在上例中,`approximateCount`在一个`switch`声明中被估值。每一个`case`都与之进行比较。因为`approximateCount`落在了12100的区间所以`naturalCount`等于`"dozens of"`值,并且此后这段执行跳出了`switch`声明。
在上例中,`approximateCount`在一个`switch`声明中被估值。每一个`case`都与之进行比较。因为`approximateCount`落在了 12100 的区间,所以`naturalCount`等于`"dozens of"`值,并且此后这段执行跳出了`switch`声明。
> 注意:
> 闭区间操作符(`...`)以及半开区间操作符(`..<`)功能被重载去返回`IntervalType`或`Range`。一个区间可以决定他是否包含特定的元素,就像当匹配一个`switch`声明的`case`一样。区间是一个连续值的集合,可以用`for-in`语句遍历它。
@ -471,7 +423,7 @@ default:
// 输出 "(1, 1) is inside the box"
```
![image](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/coordinateGraphSimple_2x.png)
![image](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/coordinateGraphSimple_2x.png)
在上面的例子中,`switch`语句会判断某个点是否是原点(0, 0)是否在红色的x轴上是否在黄色y轴上是否在一个以原点为中心的4x4的矩形里或者在这个矩形外面。
@ -498,7 +450,7 @@ case let (x, y):
// 输出 "on the x-axis with an x value of 2"
```
![image](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/coordinateGraphMedium_2x.png)
![image](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/coordinateGraphMedium_2x.png)
在上面的例子中,`switch`语句会判断某个点是否在红色的x轴上是否在黄色y轴上或者不在坐标轴上。
@ -508,8 +460,6 @@ case let (x, y):
请注意,这个`switch`语句不包含默认分支。这是因为最后一个 case ——`case let(x, y)`声明了一个可以匹配余下所有值的元组。这使得`switch`语句已经完备了,因此不需要再书写默认分支。
在上面的例子中,`x`和`y`是常量,这是因为没有必要在其对应的 case 分支中修改它们的值。然而,它们也可以是变量——程序将会创建临时变量,并用相应的值初始化它。修改这些变量只会影响其对应的 case 分支。
<a name="where"></a>
#### Where
@ -530,7 +480,7 @@ case let (x, y):
// 输出 "(1, -1) is on the line x == -y"
```
![image](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/coordinateGraphComplex_2x.png)
![image](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/coordinateGraphComplex_2x.png)
在上面的例子中,`switch`语句会判断某个点是否在绿色的对角线`x == y`上,是否在紫色的对角线`x == -y`上,或者不在对角线上。
@ -557,7 +507,7 @@ case let (x, y):
`continue`语句告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。就好像在说“本次循环迭代我已经执行完了”,但是并不会离开整个循环体。
> 注意:
> 在一个带有条件和递增的for循环体中调用`continue`语句后,迭代增量仍然会被计算求值。循环体继续像往常一样工作,仅仅只是循环体中的执行代码会被跳过。
> 在一个带有条件和递增的 for 循环体中,调用`continue`语句后,迭代增量仍然会被计算求值。循环体继续像往常一样工作,仅仅只是循环体中的执行代码会被跳过。
下面的例子把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句:
@ -573,7 +523,7 @@ for character in puzzleInput.characters {
}
}
print(puzzleOutput)
// 输出 "grtmndsthnklk"
// 输出 "grtmndsthnklk"
```
在上面的代码中,只要匹配到元音字母或者空格字符,就调用`continue`语句,使本次循环迭代结束,从新开始下次循环迭代。这种行为使`switch`匹配到元音字母和空格字符时不做处理,而不是让每一个匹配到的字符都被打印。
@ -668,11 +618,9 @@ print(description)
产生一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,并且该标签后面还需带着一个冒号。下面是一个`while`循环体的语法,同样的规则适用于所有的循环体和`switch`代码块。
```swift
label name: while condition {
statements
}
```
> `label name`: while `condition` {
> `statements`
> }
下面的例子是在一个带有标签的`while`循环体中调用`break`和`continue`语句,该循环体是前面章节中*蛇和梯子*的改编版本。这次,游戏增加了一条额外的规则:
@ -682,7 +630,7 @@ label name: while condition {
游戏的棋盘和之前一样:
![image](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/snakesAndLadders_2x.png)
![image](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/snakesAndLadders_2x.png)
`finalSquare`、`board`、`square`和`diceRoll`值被和之前一样的方式初始化:
@ -724,8 +672,8 @@ print("Game over!")
- 如果骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子。`continue gameLoop`语句结束本次`while`循环的迭代,开始下一次循环迭代。
- 在剩余的所有情况中,骰子数产生的都是合法的移动。玩家向前移动骰子数个方格,然后游戏逻辑再处理玩家当前是否处于蛇头或者梯子的底部。本次循环迭代结束,控制跳转到`while`循环体的条件判断语句处,再决定是否能够继续执行下次循环迭代。
> 注意:
> 如果上述的`break`语句没有使用`gameLoop`标签,那么它将会中断`switch`代码块而不是`while`循环体。使用`gameLoop`标签清晰的表明了`break`想要中断的是哪个代码块。
>注意:
如果上述的`break`语句没有使用`gameLoop`标签,那么它将会中断`switch`代码块而不是`while`循环体。使用`gameLoop`标签清晰的表明了`break`想要中断的是哪个代码块。
同时请注意,当调用`continue gameLoop`去跳转到下一次循环迭代时,这里使用`gameLoop`标签并不是严格必须的。因为在这个游戏中,只有一个循环体,所以`continue`语句会影响到哪个循环体是没有歧义的。然而,`continue`语句使用`gameLoop`标签也是没有危害的。这样做符合标签的使用规则,同时参照旁边的`break gameLoop`,能够使游戏的逻辑更加清晰和易于理解。
<a name="early_exit"></a>
@ -738,38 +686,34 @@ func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(["name": "John"])
// prints "Hello John!"
// prints "I hope the weather is nice near you."
// 输出 "Hello John!"
// 输出 "I hope the weather is nice near you."
greet(["name": "Jane", "location": "Cupertino"])
// prints "Hello Jane!"
// prints "I hope the weather is nice in Cupertino."
// 输出 "Hello Jane!"
// 输出 "I hope the weather is nice in Cupertino."
```
如果`guard`语句的条件被满足,则在保护语句的封闭大括号结束后继续执行代码。任何使用了可选绑定作为条件的一部分并被分配了值的变量或常量对于剩下的保护语句出现的代码段是可用的。
如果条件不被满足,在`else`分支上的代码就会被执行。这个分支必须转移控制以退出`guard`语句出现的代码段。它可以用控制转移语句如`return`,`break`,`continue`或者`throw`做这件事,或者调用一个不返回的方法或函数,例如`fatalError()`。
相比于可以实现同样功能的`if`语句,按需使用`guard`语句会提升我们代码的可靠性。
它可以使你的代码连贯的被执行而不需要将它包在`else`块中,它可以使你处理违反要求的代码使其接近要求。
相比于可以实现同样功能的`if`语句,按需使用`guard`语句会提升我们代码的可靠性。它可以使你的代码连贯的被执行而不需要将它包在`else`块中,它可以使你处理违反要求的代码接近要求。
<a name="checking_api_availability"></a>
## 检测 API 可用性
Swift 有检查 API 可用性的内置支持,这可以确保我们不会不小心地使用对于当前部署目标不可用的 API。
编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 APISwift 会在编译报错。
编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 APISwift 会在编译报错。
我们使用一个可用性条件在一个`if`或`guard`语句中去有条件的执行一段代码,这取决于我们想要使用的 API 是否在运行时是可用的。编译器使用从可用性条件语句中获取的信息去验证在代码块中调用的 API 是否都可用。
@ -781,14 +725,14 @@ if #available(iOS 9, OSX 10.10, *) {
}
```
以上可用性条件指定在 iOS 系统上`if`段的代码仅在 iOS 9 及更高版本的系统上执行;在 OS X在 OS X v10.10 及更高版本的系统上执行。最后一个参数,`*`,是必须写的,用于处理未来潜在的平台
以上可用性条件指定在 iOS`if`段的代码仅在 iOS 9 及更高可运行;在 OS X仅在 OS X v10.10 及更高可运行。最后一个参数,`*`,是必须的并且指定在任何其他平台上,`if`段的代码在最小可用部署目标指定项目中执行
在它的一般形式中,可用性条件获取了一系列平台名字和版本。平台名字可以是`iOS``OSX`或`watchOS`。除了特定的主板本号像 iOS 8我们可以指定较小的版本号像 iOS 8.3 以及 OS X v10.10.3。
在它普遍的形式中,可用性条件获取了平台名字和版本的清单。平台名字可以是`iOS``OSX`或`watchOS`。除了特定的主板本号像 iOS 8我们可以指定较小的版本号像iOS 8.3 以及 OS X v10.10.3。
```swift
if #available(platform name version, ..., *) {
statements to execute if the APIs are available
if #available(`platform name` `version`, `...`, *) {
`statements to execute if the APIs are available`
} else {
fallback statements to execute if the APIs are unavailable
`fallback statements to execute if the APIs are unavailable`
}
```

View File

@ -24,7 +24,7 @@
Swift 统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以既当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值可以被修改。
在 Swift 中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。
在 Swift 中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。
<a name="Defining_and_Calling_Functions"></a>
## 函数的定义与调用Defining and Calling Functions
@ -55,7 +55,7 @@ print(sayHello("Brian"))
调用 `sayHello(_:)` 函数时,在圆括号中传给它一个 `String` 类型的实参,例如 `sayHello("Anna")`。因为这个函数返回一个 `String` 类型的值,`sayHello` 可以被包含在 `print(_:separator:terminator:)` 的调用中,用来输出这个函数的返回值,正如上面所示。
`sayHello(_:)` 的函数体中,先定义了一个新的名为 `greeting``String` 常量,同时赋值了给 `personName`一个简单问候消息。然后用 `return` 关键字把这个问候返回出去。一旦 `return greeting` 被调用,该函数结束它的执行并返回 `greeting` 的当前值。
`sayHello(_:)` 的函数体中,先定义了一个新的名为 `greeting``String` 常量,同时,把对 `personName` 的问候消息赋值给了 `greeting` 。然后用 `return` 关键字把这个问候返回出去。一旦 `return greeting` 被调用,该函数结束它的执行并返回 `greeting` 的当前值。
你可以用不同的输入值多次调用 `sayHello(_:)`。上面的例子展示的是用`"Anna"``"Brian"`调用的结果,该函数分别返回了不同的结果。
@ -92,7 +92,7 @@ print(sayHelloWorld())
函数可以有多种输入参数,这些参数被包含在函数的括号之中,以逗号分隔。
这个函数取得一个人的名字和是否被招呼作为输入,并对那个人返回适当问候语:
这个函数一个人名和是否已经打过招呼作为输入,并返回对这个人的适当问候语:
```swift
func sayHello(personName: String, alreadyGreeted: Bool) -> String {

View File

@ -76,7 +76,7 @@ var reversed = names.sort(backwards)
如果第一个字符串(`s1`)大于第二个字符串(`s2``backwards(_:_:)`函数返回`true`,表示在新的数组中`s1`应该出现在`s2`前。对于字符串中的字符来说,“大于”表示“按照字母顺序较晚出现”。这意味着字母`"B"`大于字母`"A"`,字符串`"Tom"`大于字符串`"Tim"`。该闭包将进行字母逆序排序,`"Barry"`将会排在`"Alex"`之前。
然而,这是一个相当冗长的方式,本质上只是写了一个单表达式函数 (`a > b`)。在下面的例子中,利用闭表达式语法可以更好地构造一个内联排序闭包。
然而,这是一个相当冗长的方式,本质上只是写了一个单表达式函数 (`a > b`)。在下面的例子中,利用闭表达式语法可以更好地构造一个内联排序闭包。
<a name="closure_expression_syntax"></a>
### 闭包表达式语法Closure Expression Syntax

View File

@ -38,13 +38,13 @@ Swift 中类和结构体有很多共同点。共同处在于:
* 通过扩展以增加默认实现的功能
* 实现协议以提供某种标准功能
更多信息请参见[属性](./10_Properties.html)[方法](./11_Methods.html)[下标脚本](./12_Subscripts.html)[构造过程](./14_Initialization.html)[扩展](./21_Extensions.html),和[协议](./22_Protocols.html)。
更多信息请参见[属性](./10_Properties.html)[方法](./11_Methods.html)[下标](./12_Subscripts.html)[构造过程](./14_Initialization.html)[扩展](./21_Extensions.html),和[协议](./22_Protocols.html)。
与结构体相比,类还有如下的附加功能:
* 继承允许一个类继承另一个类的特征
* 类型转换允许在运行时检查和解释一个类实例的类型
* 构器允许一个类实例释放任何其所被分配的资源
* 构器允许一个类实例释放任何其所被分配的资源
* 引用计数允许对一个类的多次引用
更多信息请参见[继承](./13_Inheritance.html)[类型转换](./19_Type_Casting.html)[析构过程](./15_Deinitialization.html),和[自动引用计数](./16_Automatic_Reference_Counting.html)。

View File

@ -1,431 +1,438 @@
# 属性 (Properties)
---
> 1.0
> 翻译:[shinyzhu](https://github.com/shinyzhu)
> 校对:[pp-prog](https://github.com/pp-prog) [yangsiy](https://github.com/yangsiy)
> 2.0
> 翻译+校对:[yangsiy](https://github.com/yangsiy)
> 2.1
> 翻译:[buginux](https://github.com/buginux)
> 校对:[shanks](http://codebuild.me)2015-10-29
本页包含内容:
- [存储属性Stored Properties](#stored_properties)
- [计算属性Computed Properties](#computed_properties)
- [属性观察器Property Observers](#property_observers)
- [全局变量和局部变量Global and Local Variables](#global_and_local_variables)
- [类型属性Type Properties](#type_properties)
*属性*将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,而计算属性计算(不是存储)一个值。计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体。
存储属性和计算属性通常与特定类型的实例关联。但是,属性也可以直接作用于类型本身,这种属性称为类型属性。
另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己定义的存储属性上,也可以添加到从父类继承的属性上。
<a name="stored_properties"></a>
## 存储属性
简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。存储属性可以是*变量存储属性*(用关键字`var`定义),也可以是*常量存储属性*(用关键字`let`定义)。
可以在定义存储属性的时候指定默认值,请参考[默认构造器](./14_Initialization.html#default_initializers)一节。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值,请参考[构造过程中常量属性的修改](./14_Initialization.html#assigning_constant_properties_during_initialization)一节。
下面的例子定义了一个名为`FixedLengthRange`的结构体,它描述了一个在创建后无法修改值域宽度的区间:
```swift
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// 该区间表示整数012
rangeOfThreeItems.firstValue = 6
// 该区间现在表示整数678
```
`FixedLengthRange`的实例包含一个名为`firstValue`的变量存储属性和一个名为`length`的常量存储属性。在上面的例子中,`length`在创建实例的时候被初始化,因为它是一个常量存储属性,所以之后无法修改它的值。
<a name="stored_properties_of_constant_structure_instances"></a>
### 常量结构体的存储属性
如果创建了一个结构体的实例并将其赋值给一个常量,则无法修改该实例的任何属性,即使定义了变量存储属性:
```swift
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// 该区间表示整数0123
rangeOfFourItems.firstValue = 6
// 尽管 firstValue 是个变量属性,这里还是会报错
```
因为`rangeOfFourItems`被声明成了常量(用`let`关键字),即使`firstValue`是一个变量属性,也无法再修改它了。
这种行为是由于结构体struct属于*值类型*。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。
属于*引用类型*的类class则不一样。把一个引用类型的实例赋给一个常量后仍然可以修改该实例的变量属性。
<a name="lazy_stored_properties"></a>
### 延迟存储属性
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用`lazy`来标示一个延迟存储属性。
> 注意
> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
延迟属性很有用,当属性的值依赖于在实例的构造过程结束后才会知道具体值的外部因素时,或者当获得属性的初始值需要复杂或大量计算时,可以只在需要的时候计算它。
下面的例子使用了延迟存储属性来避免复杂类中不必要的初始化。例子中定义了`DataImporter``DataManager`两个类,下面是部分代码:
```swift
class DataImporter {
/*
DataImporter 是一个负责将外部文件中的数据导入的类。
这个类的初始化会消耗不少时间
*/
var fileName = "data.txt"
// 这里会提供数据导入功能
}
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
// 这里会提供数据管理功能
}
let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
// DataImporter 实例的 importer 属性还没有被创建
```
`DataManager`类包含一个名为`data`的存储属性,初始值是一个空的字符串(`String`)数组。这里没有给出全部代码,只需知道`DataManager`类的目的是管理和提供对这个字符串数组的访问即可。
`DataManager`的一个功能是从文件导入数据。该功能由`DataImporter`类提供,`DataImporter`完成初始化需要消耗不少时间:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。
`DataManager`管理数据时也可能不从文件中导入数据。所以当`DataManager`的实例被创建时,没必要创建一个`DataImporter`的实例,更明智的做法是第一次用到`DataImporter`的时候才去创建它。
由于使用了`lazy``importer`属性只有在第一次被访问的时候才被创建。比如访问它的属性`fileName`时:
```swift
print(manager.importer.fileName)
// DataImporter 实例的 importer 属性现在被创建了
// 输出 "data.txt”
```
> 注意
> 如果一个被标记为`lazy`的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。
<a name="stored_properties_and_instance_variables"></a>
### 存储属性和实例变量
如果您有过 Objective-C 经验,应该知道 Objective-C 为类实例存储值和引用提供两种方法。除了属性之外,还可以使用实例变量作为属性值的后端存储。
Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。
<a name="computed_properties"></a>
## 计算属性
除存储属性外,类、结构体和枚举可以定义*计算属性*。计算属性不直接存储值,而是提供一个 getter 和一个可选的 setter来间接获取和设置其他属性或变量的值。
```swift
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// 输出 "square.origin is now at (10.0, 10.0)”
```
这个例子定义了 3 个结构体来描述几何形状:
- `Point`封装了一个`(x, y)`的坐标
- `Size`封装了一个`width`和一个`height`
- `Rect`表示一个有原点和尺寸的矩形
`Rect`也提供了一个名为`center`的计算属性。一个矩形的中心点可以从原点(`origin`)和尺寸(`size`)算出,所以不需要将它以显式声明的`Point`来保存。`Rect`的计算属性`center`提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。
上述例子中创建了一个名为`square``Rect`实例,初始值原点是`(0, 0)`,宽度高度都是`10`。如下图中蓝色正方形所示。
`square``center`属性可以通过点运算符(`square.center`)来访问,这会调用该属性的 getter 来获取它的值。跟直接返回已经存在的值不同getter 实际上通过计算然后返回一个新的`Point`来表示`square`的中心点。如代码所示,它正确返回了中心点`(5, 5)`
`center`属性之后被设置了一个新的值`(15, 15)`,表示向右上方移动正方形到如下图橙色正方形所示的位置。设置属性`center`的值会调用它的 setter 来修改属性`origin``x``y`的值,从而实现移动正方形到新的位置。
<img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/computedProperties_2x.png" alt="Computed Properties sample" width="388" height="387" />
<a name="shorthand_setter_declaration"></a>
### 便捷 setter 声明
如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称`newValue`。下面是使用了便捷 setter 声明的`Rect`结构体代码:
```swift
struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
```
<a name="readonly_computed_properties"></a>
### 只读计算属性
只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。
> 注意
> 必须使用`var`关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。
只读计算属性的声明可以去掉`get`关键字和花括号:
```swift
struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
return width * height * depth
}
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// 输出 "the volume of fourByFiveByTwo is 40.0"
```
这个例子定义了一个名为`Cuboid`的结构体,表示三维空间的立方体,包含`width``height``depth`属性。结构体还有一个名为`volume`的只读计算属性用来返回立方体的体积。为`volume`提供 setter 毫无意义,因为无法确定如何修改`width``height``depth`三者的值来匹配新的`volume`。然而,`Cuboid`提供一个只读计算属性来让外部用户直接获取体积是很有用的。
<a name="property_observers"></a>
## 属性观察器
*属性观察器*监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新值和当前值相同的时候也不例外。
可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。属性重写请参考[重写](./13_Inheritance.html#overriding)。
> 注意
> 不需要为非重写的计算属性添加属性观察器,因为可以通过它的 setter 直接监控和响应值的变化。
可以为属性添加如下的一个或全部观察器:
- `willSet`在新的值被设置之前调用
- `didSet`在新的值被设置之后立即调用
`willSet`观察器会将新的属性值作为常量参数传入,在`willSet`的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称`newValue`表示。
类似地,`didSet`观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名`oldValue`
> 注意
> 父类的属性在子类的构造器中被赋值时,它在父类中的`willSet`和`didSet`观察器会被调用。
> 有关构造器代理的更多信息,请参考[值类型的构造器代理](./14_Initialization.html#initializer_delegation_for_value_types)和[类的构造器代理规则](./14_Initialization.html#initializer_delegation_for_class_types)
这里是一个`willSet``didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计一个人步行时的总步数。这个类可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用
```swift
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps
```
`StepCounter`类定义了一个`Int`类型的属性`totalSteps`,它是一个存储属性,包含`willSet``didSet`观察器。
`totalSteps`被设置新值的时候,它的`willSet``didSet`观察器都会被调用,甚至新值和当前值完全相同时也会被调用。
例子中的`willSet`观察器将表示新值的参数自定义为`newTotalSteps`,这个观察器只是简单的将新的值输出。
`didSet`观察器在`totalSteps`的值改变后被调用,它把新值和旧值进行对比,如果总步数增加了,就输出一个消息表示增加了多少步。`didSet`没有为旧值提供自定义名称,所以默认值`oldValue`表示旧值的参数名
> 注意
> 如果在一个属性的`didSet`观察器里为它赋值,这个值会替换之前设置的值。
<a name="global_and_local_variables"></a>
##全局变量和局部变量
计算属性和属性观察器所描述的功能也可以用于*全局变量*和*局部变量*。全局变量是在函数、方法、闭包或任何类型之外定义的变量。局部变量是在函数、方法或闭包内部定义的变量。
前面章节提到的全局或局部变量都属于存储型变量,跟存储属性类似,它为特定类型的值提供存储空间,并允许读取和写入。
另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器。计算型变量跟计算属性一样,返回一个计算结果而不是存储值,声明格式也完全一样。
> 注意
> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`lazy`修饰符。
> 局部范围的常量或变量从不延迟计算。
<a name="type_properties"></a>
##类型属性
实例属性属于一个特定类型的实例,每创建一个实例,实例都拥有属于自己的一套属性值,实例之间的属性相互独立。
也可以为类型本身定义属性,无论创建了多少个该类型的实例,这些属性都只有唯一一份。这种属性就是*类型属性*。
类型属性用于定义某个类型所有实例共享的数据,比如所有实例都能用的一个常量(就像 C 语言中的静态常量),或者所有实例都能访问的一个变量(就像 C 语言中的静态变量)。
存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算型属性一样只能定义成变量属性。
> 注意
> 跟实例的存储型属性不同,必须给存储型类型属性指定默认值,因为类型本身没有构造器,也就无法在初始化过程中使用构造器给类型属性赋值。
> 存储型类型属性是延迟初始化的,它们只有在第一次被访问的时候才会被初始化。即使它们被多个线程同时访问,系统也保证只会对其进行一次初始化,并且不需要对其使用`lazy`修饰符。
<a name="type_property_syntax"></a>
###类型属性语法
在 C 或 Objective-C 中,与某个类型关联的静态常量和静态变量,是作为全局(*global*)静态变量定义的。但是在 Swift 中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。
使用关键字`static`来定义类型属性。在为类定义计算型类型属性时,可以改用关键字`class`来支持子类对父类的实现进行重写。下面的例子演示了存储型和计算型类型属性的语法:
```swift
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 1
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 6
}
}
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 27
}
class var overrideableComputedTypeProperty: Int {
return 107
}
}
```
> 注意
> 例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟计算型实例属性的语法相同。
<a name="querying_and_setting_type_properties"></a>
###获取和设置类型属性的值
跟实例属性一样,类型属性也是通过点运算符来访问。但是,类型属性是通过类型本身来访问,而不是通过实例。比如:
```swift
print(SomeStructure.storedTypeProperty)
// 输出 "Some value."
SomeStructure.storedTypeProperty = "Another value."
print(SomeStructure.storedTypeProperty)
// 输出 "Another value.”
print(SomeEnumeration.computedTypeProperty)
// 输出 "6"
print(SomeClass.computedTypeProperty)
// 输出 "27"
```
下面的例子定义了一个结构体,使用两个存储型类型属性来表示两个声道的音量,每个声道具有`0``10`之间的整数音量。
下图展示了如何把两个声道结合来模拟立体声的音量。当声道的音量是`0`,没有一个灯会亮;当声道的音量是`10`,所有灯点亮。本图中,左声道的音量是`9`,右声道的音量是`7`
<img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/staticPropertiesVUMeter_2x.png" alt="Static Properties VUMeter" width="243" height="357" />
上面所描述的声道模型使用`AudioChannel`结构体的实例来表示:
```swift
struct AudioChannel {
static let thresholdLevel = 10
static var maxInputLevelForAllChannels = 0
var currentLevel: Int = 0 {
didSet {
if currentLevel > AudioChannel.thresholdLevel {
// 将当前音量限制在阀值之内
currentLevel = AudioChannel.thresholdLevel
}
if currentLevel > AudioChannel.maxInputLevelForAllChannels {
// 存储当前音量作为新的最大输入音量
AudioChannel.maxInputLevelForAllChannels = currentLevel
}
}
}
}
```
结构`AudioChannel`定义了 2 个存储型类型属性来实现上述功能。第一个是`thresholdLevel`,表示音量的最大上限阈值,它是一个值为`10`的常量,对所有实例都可见,如果音量高于`10`,则取最大上限值`10`(见后面描述)。
第二个类型属性是变量存储型属性`maxInputLevelForAllChannels`,它用来表示所有`AudioChannel`实例的最大音量,初始值是`0`
`AudioChannel`也定义了一个名为`currentLevel`的存储型实例属性,表示当前声道现在的音量,取值为`0``10`
属性`currentLevel`包含`didSet`属性观察器来检查每次设置后的属性值,它做如下两个检查:
- 如果`currentLevel`的新值大于允许的阈值`thresholdLevel`,属性观察器将`currentLevel`的值限定为阈值`thresholdLevel`
- 如果修正后的`currentLevel`值大于静态类型属性`maxInputLevelForAllChannels`的值,属性观察器就将新值保存在`maxInputLevelForAllChannels`
> 注意
> 在第一个检查过程中,`didSet`属性观察器将`currentLevel`设置成了不同的值,但这不会造成属性观察器被再次调用。
可以使用结构体`AudioChannel`创建两个声道`leftChannel``rightChannel`,用以表示立体声系统的音量:
```swift
var leftChannel = AudioChannel()
var rightChannel = AudioChannel()
```
如果将左声道的`currentLevel`设置成`7`,类型属性`maxInputLevelForAllChannels`也会更新成`7`
```swift
leftChannel.currentLevel = 7
print(leftChannel.currentLevel)
// 输出 "7"
print(AudioChannel.maxInputLevelForAllChannels)
// 输出 "7"
```
如果试图将右声道的`currentLevel`设置成`11`,它会被修正到最大值`10`,同时`maxInputLevelForAllChannels`的值也会更新到`10`
```swift
rightChannel.currentLevel = 11
print(rightChannel.currentLevel)
// 输出 "10"
print(AudioChannel.maxInputLevelForAllChannels)
// 输出 "10"
```
# 属性 (Properties)
---
> 1.0
> 翻译:[shinyzhu](https://github.com/shinyzhu)
> 校对:[pp-prog](https://github.com/pp-prog) [yangsiy](https://github.com/yangsiy)
> 2.0
> 翻译+校对:[yangsiy](https://github.com/yangsiy)
> 2.1
> 翻译:[buginux](https://github.com/buginux)
> 校对:[shanks](http://codebuild.me)2015-10-29
> 2.2
> 翻译:[saitjr](https://github.com/saitjr)2016-04-11
本页包含内容:
- [存储属性Stored Properties](#stored_properties)
- [计算属性Computed Properties](#computed_properties)
- [属性观察器Property Observers](#property_observers)
- [全局变量和局部变量Global and Local Variables](#global_and_local_variables)
- [类型属性Type Properties](#type_properties)
*属性*将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,而计算属性计算(不是存储)一个值。计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体。
存储属性和计算属性通常与特定类型的实例关联。但是,属性也可以直接作用于类型本身,这种属性称为类型属性。
另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己定义的存储属性上,也可以添加到从父类继承的属性上。
<a name="stored_properties"></a>
## 存储属性
简单来说,一个存储属性就是存储在特定类或结构体实例里的一个常量或变量。存储属性可以是*变量存储属性*(用关键字 `var` 定义),也可以是*常量存储属性*(用关键字 `let` 定义)。
可以在定义存储属性的时候指定默认值,请参考[默认构造器](./14_Initialization.html#default_initializers)一节。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值,请参考[构造过程中常量属性的修改](./14_Initialization.html#assigning_constant_properties_during_initialization)一节。
下面的例子定义了一个名为 `FixedLengthRange` 的结构体,它描述了一个用于表示整型范围的常量,在创建后就不能进行修改:
```swift
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// 该区间表示整数012
rangeOfThreeItems.firstValue = 6
// 该区间现在表示整数678
```
`FixedLengthRange` 的实例包含一个名为 `firstValue` 的变量存储属性和一个名为 `length` 的常量存储属性。在上面的例子中,`length` 在创建实例的时候被初始化,因为它是一个常量存储属性,所以之后无法修改它的值。
<a name="stored_properties_of_constant_structure_instances"></a>
### 常量结构体的存储属性
如果创建了一个结构体的实例并将其赋值给一个常量,则无法修改该实例的任何属性,即使有属性被声明为变量也不行:
```swift
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// 该区间表示整数0123
rangeOfFourItems.firstValue = 6
// 尽管 firstValue 是个变量属性,这里还是会报错
```
因为 `rangeOfFourItems` 被声明成了常量(用 `let` 关键字),即使 `firstValue` 是一个变量属性,也无法再修改它了。
这种行为是由于结构体struct属于*值类型*。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。
属于*引用类型*的类class则不一样。把一个引用类型的实例赋给一个常量后仍然可以修改该实例的变量属性。
<a name="lazy_stored_properties"></a>
### 延迟存储属性
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用 `lazy` 来标示一个延迟存储属性。
> 注意
> 必须将延迟存储属性声明成变量(使用 `var` 关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
延迟属性很有用,当属性的值依赖于在实例的构造过程结束后才会知道影响值的外部因素时,或者当获得属性的初始值需要复杂或大量计算时,可以只在需要的时候计算它
下面的例子使用了延迟存储属性来避免复杂类中不必要的初始化。例子中定义了 `DataImporter``DataManager` 两个类,下面是部分代码:
```swift
class DataImporter {
/*
DataImporter 是一个负责将外部文件中的数据导入的类。
这个类的初始化会消耗不少时间。
*/
var fileName = "data.txt"
// 这里会提供数据导入功能
}
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
// 这里会提供数据管理功能
}
let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
// DataImporter 实例的 importer 属性还没有被创建
```
`DataManager` 类包含一个名为 `data` 的存储属性,初始值是一个空的字符串(`String`)数组。这里没有给出全部代码,只需知道 `DataManager` 类的目的是管理和提供对这个字符串数组的访问即可。
`DataManager` 的一个功能是从文件导入数据。该功能由 `DataImporter` 类提供,`DataImporter` 完成初始化需要消耗不少时间:因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。
`DataManager` 管理数据时也可能不从文件中导入数据。所以当 `DataManager` 的实例被创建时,没必要创建一个 `DataImporter` 的实例,更明智的做法是第一次用到 `DataImporter` 的时候才去创建它。
由于使用了 `lazy` `importer` 属性只有在第一次被访问的时候才被创建。比如访问它的属性 `fileName` 时:
```swift
print(manager.importer.fileName)
// DataImporter 实例的 importer 属性现在被创建了
// 输出 "data.txt”
```
> 注意
> 如果一个被标记为 `lazy` 的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。
<a name="stored_properties_and_instance_variables"></a>
### 存储属性和实例变量
如果您有过 Objective-C 经验,应该知道 Objective-C 为类实例存储值和引用提供两种方法。除了属性之外,还可以使用实例变量作为属性值的后端存储。
Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。
<a name="computed_properties"></a>
## 计算属性
除存储属性外,类、结构体和枚举可以定义*计算属性*。计算属性不直接存储值,而是提供一个 getter 和一个可选的 setter来间接获取和设置其他属性或变量的值。
```swift
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// 输出 "square.origin is now at (10.0, 10.0)”
```
这个例子定义了 3 个结构体来描述几何形状:
- `Point` 封装了一个 `(x, y)` 的坐标
- `Size` 封装了一个 `width` 和一个 `height`
- `Rect` 表示一个有原点和尺寸的矩形
`Rect`也提供了一个名为`center` 的计算属性。一个矩形的中心点可以从原点(`origin`)和大小(`size`)算出,所以不需要将它以显式声明的 `Point` 来保存。`Rect` 的计算属性 `center` 提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。
上述例子中创建了一个名为 `square``Rect` 实例,初始值原点是 `(0, 0)`,宽度高度都是 `10`。如下图中蓝色正方形所示。
`square``center` 属性可以通过点运算符(`square.center`)来访问,这会调用该属性的 getter 来获取它的值。跟直接返回已经存在的值不同getter 实际上通过计算然后返回一个新的 `Point` 来表示 `square` 的中心点。如代码所示,它正确返回了中心点 `(5, 5)`
`center` 属性之后被设置了一个新的值 `(15, 15)`,表示向右上方移动正方形到如下图橙色正方形所示的位置。设置属性`center`的值会调用它的 setter 来修改属性 `origin``x``y` 的值,从而实现移动正方形到新的位置。
<img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/computedProperties_2x.png" alt="Computed Properties sample" width="388" height="387" />
<a name="shorthand_setter_declaration"></a>
### 便捷 setter 声明
如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称 `newValue`。下面是使用了便捷 setter 声明的 `Rect` 结构体代码:
```swift
struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
```
<a name="readonly_computed_properties"></a>
### 只读计算属性
只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。
> 注意
> 必须使用 `var` 关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。`let` 关键字只用来声明常量属性,表示初始化后再也无法修改的值。
只读计算属性的声明可以去掉 `get` 关键字和花括号:
```swift
struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
return width * height * depth
}
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// 输出 "the volume of fourByFiveByTwo is 40.0"
```
这个例子定义了一个名为 `Cuboid` 的结构体,表示三维空间的立方体,包含 `width``height``depth` 属性。结构体还有一个名为 `volume` 的只读计算属性用来返回立方体的体积。为 `volume` 提供 setter 毫无意义,因为无法确定如何修改 `width``height``depth` 三者的值来匹配新的 `volume`。然而,`Cuboid` 提供一个只读计算属性来让外部用户直接获取体积是很有用的。
<a name="property_observers"></a>
## 属性观察器
*属性观察器*监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。
可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。你不必为非重写的计算属性添加属性观察器,因为可以通过它的 setter 直接监控和响应值的变化。 属性重写请参考[重写](./13_Inheritance.html#overriding)。
可以为属性添加如下的一个或全部观察器:
- `willSet` 在新的值被设置之前调用
- `didSet` 在新的值被设置之后立即调用
`willSet` 观察器会将新的属性值作为常量参数传入,在 `willSet` 的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称 `newValue` 表示
同样,`didSet` 观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名 `oldValue`。如果在 `didSet` 方法中再次对该属性赋值,那么新值会覆盖旧的值
> 注意
> 父类的属性在子类的构造器中被赋值时,它在父类中的 `willSet` 和 `didSet` 观察器会被调用,随后才会调用子类的观察器。在父类书初始化方法调用之前,子类给属性赋值时,观察器不会被调用。
> 有关构造器代理的更多信息,请参考[值类型的构造器代理](./14_Initialization.html#initializer_delegation_for_value_types)和[类的构造器代理规则](./14_Initialization.html#initializer_delegation_for_class_types)。
下面是一个 `willSet``didSet` 实际运用的例子,其中定义了一个名为 `StepCounter` 的类,用来统计一个人步行时的总步数。这个类可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。
```swift
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps
```
`StepCounter` 类定义了一个 `Int` 类型的属性 `totalSteps`,它是一个存储属性,包含 `willSet``didSet` 观察器
`totalSteps` 被设置新值的时候,它的 `willSet``didSet` 观察器都会被调用,即使新值和当前值完全相同时也会被调用。
例子中的 `willSet` 观察器将表示新值的参数自定义为 `newTotalSteps`,这个观察器只是简单的将新的值输出。
`didSet` 观察器在 `totalSteps` 的值改变后被调用,它把新值和旧值进行对比,如果总步数增加了,就输出一个消息表示增加了多少步。`didSet` 没有为旧值提供自定义名称,所以默认值 `oldValue` 表示旧值的参数名。
>注意
>
>如果将属性通过 in-out 方式传入函数,`willSet` 和 `didSet` 也会调用。这是因为 in-out 参数采用了拷入拷出模式:即在函数内部使用的是参数的 copy函数结束后又对参数重新赋值。关于 in-out 参数详细的介绍,请参考[输入输出参数](../chapter3/05_Declarations.html#in-out_parameters)
<a name="global_and_local_variables"></a>
##全局变量和局部变量
计算属性和属性观察器所描述的功能也可以用于*全局变量*和*局部变量*。全局变量是在函数、方法、闭包或任何类型之外定义的变量。局部变量是在函数、方法或闭包内部定义的变量。
前面章节提到的全局或局部变量都属于存储型变量,跟存储属性类似,它为特定类型的值提供存储空间,并允许读取和写入。
另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器。计算型变量跟计算属性一样,返回一个计算结果而不是存储值,声明格式也完全一样。
> 注意
> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`lazy`修饰符。
> 局部范围的常量或变量从不延迟计算。
<a name="type_properties"></a>
##类型属性
实例属性属于一个特定类型的实例,每创建一个实例,实例都拥有属于自己的一套属性值,实例之间的属性相互独立。
也可以为类型本身定义属性,无论创建了多少个该类型的实例,这些属性都只有唯一一份。这种属性就是*类型属性*。
类型属性用于定义某个类型所有实例共享的数据,比如所有实例都能用的一个常量(就像 C 语言中的静态常量),或者所有实例都能访问的一个变量(就像 C 语言中的静态变量)。
存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算型属性一样只能定义成变量属性。
> 注意
> 跟实例的存储型属性不同,必须给存储型类型属性指定默认值,因为类型本身没有构造器,也就无法在初始化过程中使用构造器给类型属性赋值。
> 存储型类型属性是延迟初始化的,它们只有在第一次被访问的时候才会被初始化。即使它们被多个线程同时访问,系统也保证只会对其进行一次初始化,并且不需要对其使用 `lazy` 修饰符。
<a name="type_property_syntax"></a>
###类型属性语法
在 C 或 Objective-C 中,与某个类型关联的静态常量和静态变量,是作为全局(*global*)静态变量定义的。但是在 Swift 中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。
使用关键字 `static` 来定义类型属性。在为类定义计算型类型属性时,可以改用关键字 `class` 来支持子类对父类的实现进行重写。下面的例子演示了存储型和计算型类型属性的语法:
```swift
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 1
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 6
}
}
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 27
}
class var overrideableComputedTypeProperty: Int {
return 107
}
}
```
> 注意
> 例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟计算型实例属性的语法相同。
<a name="querying_and_setting_type_properties"></a>
###获取和设置类型属性的值
跟实例属性一样,类型属性也是通过点运算符来访问。但是,类型属性是通过类型本身来访问,而不是通过实例。比如:
```swift
print(SomeStructure.storedTypeProperty)
// 输出 "Some value."
SomeStructure.storedTypeProperty = "Another value."
print(SomeStructure.storedTypeProperty)
// 输出 "Another value.”
print(SomeEnumeration.computedTypeProperty)
// 输出 "6"
print(SomeClass.computedTypeProperty)
// 输出 "27"
```
下面的例子定义了一个结构体,使用两个存储型类型属性来表示两个声道的音量,每个声道具有 `0``10` 之间的整数音量。
下图展示了如何把两个声道结合来模拟立体声的音量。当声道的音量是 `0`,没有一个灯会亮;当声道的音量是 `10`,所有灯点亮。本图中,左声道的音量是 `9`,右声道的音量是 `7`
<img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/staticPropertiesVUMeter_2x.png" alt="Static Properties VUMeter" width="243" height="357" />
上面所描述的声道模型使用 `AudioChannel` 结构体的实例来表示:
```swift
struct AudioChannel {
static let thresholdLevel = 10
static var maxInputLevelForAllChannels = 0
var currentLevel: Int = 0 {
didSet {
if currentLevel > AudioChannel.thresholdLevel {
// 将当前音量限制在阀值之内
currentLevel = AudioChannel.thresholdLevel
}
if currentLevel > AudioChannel.maxInputLevelForAllChannels {
// 存储当前音量作为新的最大输入音量
AudioChannel.maxInputLevelForAllChannels = currentLevel
}
}
}
}
```
结构 `AudioChannel` 定义了 2 个存储型类型属性来实现上述功能。第一个是 `thresholdLevel`,表示音量的最大上限阈值,它是一个值为 `10` 的常量,对所有实例都可见,如果音量高于 `10`,则取最大上限值 `10`(见后面描述)。
第二个类型属性是变量存储型属性 `maxInputLevelForAllChannels`,它用来表示所有 `AudioChannel` 实例的最大音量,初始值是`0`
`AudioChannel` 也定义了一个名为 `currentLevel` 的存储型实例属性,表示当前声道现在的音量,取值为 `0``10`
属性 `currentLevel` 包含 `didSet` 属性观察器来检查每次设置后的属性值,它做如下两个检查:
- 如果 `currentLevel` 的新值大于允许的阈值 `thresholdLevel`,属性观察器将 `currentLevel` 的值限定为阈值 `thresholdLevel`
- 如果修正后的 `currentLevel` 值大于静态类型属性 `maxInputLevelForAllChannels` 的值,属性观察器就将新值保存在 `maxInputLevelForAllChannels` 中。
> 注意
> 在第一个检查过程中,`didSet` 属性观察器将 `currentLevel` 设置成了不同的值,但这不会造成属性观察器被再次调用。
可以使用结构体 `AudioChannel` 创建两个声道 `leftChannel``rightChannel`,用以表示立体声系统的音量
```swift
var leftChannel = AudioChannel()
var rightChannel = AudioChannel()
```
如果将左声道的 `currentLevel` 设置成 `7`,类型属性 `maxInputLevelForAllChannels` 也会更新成 `7`
```swift
leftChannel.currentLevel = 7
print(leftChannel.currentLevel)
// 输出 "7"
print(AudioChannel.maxInputLevelForAllChannels)
// 输出 "7"
```
如果试图将右声道的 `currentLevel` 设置成 `11`,它会被修正到最大值 `10`,同时 `maxInputLevelForAllChannels` 的值也会更新到 `10`
```swift
rightChannel.currentLevel = 11
print(rightChannel.currentLevel)
// 输出 "10"
print(AudioChannel.maxInputLevelForAllChannels)
// 输出 "10"
```

View File

@ -9,7 +9,7 @@
> 翻译+校对:[DianQK](https://github.com/DianQK)
> 2.1
> 校对:[shanks](http://codebuild.me)2015-10-29
> 翻译:[DianQK](https://github.com/DianQK)[Realank](https://github.com/Realank) 校对:[shanks](http://codebuild.me)2016-01-18
本页包含内容:
@ -84,7 +84,7 @@ class Counter {
}
```
`incrementBy(_:numverOfTimes:)`方法有两个参数: `amount``numberOfTimes`。默认情况下Swift 只把`amount`当作一个局部名称,但是把`numberOfTimes`即看作局部名称又看作外部名称。下面调用这个方法:
`incrementBy(_:numberOfTimes:)`方法有两个参数: `amount``numberOfTimes`。默认情况下Swift 只把`amount`当作一个局部名称,但是把`numberOfTimes`即看作局部名称又看作外部名称。下面调用这个方法:
```swift
let counter = Counter()
@ -141,11 +141,11 @@ if somePoint.isToTheRightOfX(1.0) {
<a name="modifying_value_types_from_within_instance_methods"></a>
### 在实例方法中修改值类型(Modifying Value Types from Within Instance Methods)
结构体和枚举是**值类型**。一般情况下,值类型的属性不能在它的实例方法中被修改。
结构体和枚举是**值类型**。默认情况下,值类型的属性不能在它的实例方法中被修改。
但是,如果你确实需要在某个特定的方法中修改结构体或者枚举的属性,你可以选择`变(mutating)`这个方法,然后方法就可以从方法内部改变它的属性;并且做的任何改变在方法结束时还会保留在原始结构中。方法还可以给它隐含的`self`属性赋一个全新的实例,这个新实例在方法结束后将替换原来的实例。
但是,如果你确实需要在某个特定的方法中修改结构体或者枚举的属性,你可以为这个方法选择`变(mutating)`行为,然后就可以从方法内部改变它的属性;并且这个方法做的任何改变都会在方法执行结束时写回到原始结构中。方法还可以给它隐含的`self`属性赋一个全新的实例,这个新实例在方法结束时会替换现存实例。
要使用`变`方法,将关键字`mutating` 放到方法的`func`关键字之前就可以了:
要使用`变`方法,将关键字`mutating` 放到方法的`func`关键字之前就可以了:
```swift
struct Point {
@ -161,9 +161,9 @@ print("The point is now at (\(somePoint.x), \(somePoint.y))")
// 打印输出: "The point is now at (3.0, 4.0)"
```
上面的`Point`结构体定义了一个可变方法mutating method`moveByX(_:y:)`来移动。该方法被调用时修改了这个点,而不是返回一个新的点。方法定义时加上了`mutating`关键字,从而可以修改属性。
上面的`Point`结构体定义了一个可变方法 `moveByX(_:y:)` 来移动`Point`实例到给定的位置。该方法被调用时修改了这个点,而不是返回一个新的点。方法定义时加上了`mutating`关键字,从而允许修改属性。
注意,不能在结构体类型的常量上调用可变方法,因为其属性不能被改变,即使属性是变量属性,详情参见[常量结构体的存储属性](./10_Properties.html#stored_properties_of_constant_structure_instances)
注意,不能在结构体类型的常量a constant of structure type上调用可变方法,因为其属性不能被改变,即使属性是变量属性,详情参见[常量结构体的存储属性](./10_Properties.html#stored_properties_of_constant_structure_instances)
```swift
let fixedPoint = Point(x: 3.0, y: 3.0)
@ -185,7 +185,7 @@ struct Point {
}
```
新版的可变方法`moveByX(_:y:)`创建了一个新的结构它的 x 和 y 的值都被设定为目标值。调用这个版本的方法和调用上个版本的最终结果是一样的。
新版的可变方法`moveByX(_:y:)`创建了一个新的结构体实例,它的 x 和 y 的值都被设定为目标值。调用这个版本的方法和调用上个版本的最终结果是一样的。
枚举的可变方法可以把`self`设置为同一枚举类型中不同的成员:
@ -215,16 +215,16 @@ ovenLight.next()
<a name="type_methods"></a>
## 类型方法 (Type Methods)
实例方法是被类型的某个实例调用的方法。你也可以定义类型本身调用的方法,这种方法就叫做**类型方法**。声明结构体和枚举的类型方法,在方法的`func`关键字之前加上关键字`static`。类可能会用关键字`class`来允许子类重写父类的方法实现。
实例方法是被某个类型的实例调用的方法。你也可以定义类型本身调用的方法,这种方法就叫做**类型方法**Type Methods在方法的`func`关键字之前加上关键字`static`,来指定类型方法。类还可以用关键字`class`来允许子类重写父类的方法实现。
> 注意
> 在 Objective-C 中,你只能为 Objective-C 的类定义类型方法type-level methods。在 Swift 中,你可以为所有的类、结构体和枚举定义类型方法。每一个类型方法都被它所支持的类型显式包含。
> 在 Objective-C 中,你只能为 Objective-C 的类类型classes定义类型方法type-level methods。在 Swift 中,你可以为所有的类、结构体和枚举定义类型方法。每一个类型方法都被它所支持的类型显式包含。
类型方法和实例方法一样用点语法调用。但是,你是在类型层面上调用这个方法,而不是在实例层面上调用。下面是如何在`SomeClass`类上调用类型方法的例子:
类型方法和实例方法一样用点语法调用。但是,你是在类型上调用这个方法,而不是在实例上调用。下面是如何在`SomeClass`类上调用类型方法的例子:
```swift
class SomeClass {
static func someTypeMethod() {
class func someTypeMethod() {
// type method implementation goes here
}
}
@ -233,7 +233,7 @@ SomeClass.someTypeMethod()
在类型方法的方法体body`self`指向这个类型本身,而不是类型的某个实例。这意味着你可以用`self`来消除类型属性和类型方法参数之间的歧义(类似于我们在前面处理实例属性和实例方法参数时做的那样)。
一般来说,在类型方法的方法体中,任何未限定的方法和属性名称,将会指代本类中其他类型方法和类型属性。一个类型方法可以通过类型方法的名称调用本类中的类型方法,而无需在方法名称前面加上类型名称前缀。同样,也能够直接通过类型属性的名称访问本类中的类型属性,而不需要类型名称前缀
一般来说,在类型方法的方法体中,任何未限定的方法和属性名称,可以被本类中其他类型方法和类型属性引用。一个类型方法可以直接通过类型方法的名称调用本类中的其它类型方法,而无需在方法名称前面加上类型名称。类似地,在结构体和枚举中,也能够直接通过类型属性的名称访问本类中的类型属性,而不需要前面加上类型名称。
下面的例子定义了一个名为`LevelTracker`结构体。它监测玩家的游戏发展情况(游戏的不同层次或阶段)。这是一个单人游戏,但也可以存储多个玩家在同一设备上的游戏信息。
@ -264,7 +264,7 @@ struct LevelTracker {
`LevelTracker`还定义了两个类型方法与`highestUnlockedLevel`配合工作。第一个类型方法是`unlockLevel`,一旦新等级被解锁,它会更新`highestUnlockedLevel`的值。第二个类型方法是`levelIsUnlocked`,如果某个给定的等级已经被解锁,它将返回`true`。(注意,尽管我们没有使用类似`LevelTracker.highestUnlockedLevel`的写法,这个类型方法还是能够访问类型属性`highestUnlockedLevel`
除了类型属性和类型方法,`LevelTracker`还监测每个玩家的进度。它用实例属性`currentLevel`来监测玩家当前的等级。
除了类型属性和类型方法,`LevelTracker`还监测每个玩家的进度。它用实例属性`currentLevel`来监测每个玩家当前的等级。
为了便于管理`currentLevel`属性,`LevelTracker`定义了实例方法`advanceToLevel`。这个方法会在更新`currentLevel`之前检查所请求的新等级是否已经解锁。`advanceToLevel`方法返回布尔值以指示是否能够设置`currentLevel`

View File

@ -1,27 +1,31 @@
# 下标脚本Subscripts
# 下标Subscripts
-----------------
> 1.0
> 翻译:[siemenliu](https://github.com/siemenliu)
> 校对:[zq54zquan](https://github.com/zq54zquan)
> 2.0,2.1
> 翻译+校对:[shanks](http://codebuild.me)2015-10-29
> 2.0
> 翻译+校对:[shanks](http://codebuild.me)
> 2.1
> 翻译+校对:[shanks](http://codebuild.me)[Realank](https://github.com/Realank)
本页包含内容:
- [下标脚本语法](#subscript_syntax)
- [下标脚本用法](#subscript_usage)
- [下标脚本选项](#subscript_options)
- [下标语法](#subscript_syntax)
- [下标用法](#subscript_usage)
- [下标选项](#subscript_options)
*下标脚本* 可以定义在类(Class、结构体structure和枚举enumeration是访问集合collection列表list或序列sequence中元素的快捷方式。可以使用下标脚本的索引设置和获取值,不需要再调用对应的存取方法。举例来说,用下标脚本访问一个`Array`实例中的元素可以写作`someArray[index]`,访问`Dictionary`实例中的元素可以写作`someDictionary[key]`
*下标* subscripts可以定义在类(class、结构体structure和枚举enumeration是访问集合collection列表list或序列sequence中元素的快捷方式。可以使用下标的索引设置和获取值,不需要再调用对应的存取方法。举例来说,用下标访问一个`Array`实例中的元素可以写作`someArray[index]`,访问`Dictionary`实例中的元素可以写作`someDictionary[key]`
一个类型可以定义多个下标脚本,通过不同索引类型进行重载。下标脚本不限于一维,你可以定义具有多个入参的下标脚本满足自定义类型的需求。
一个类型可以定义多个下标,通过不同索引类型进行重载。下标不限于一维,你可以定义具有多个入参的下标满足自定义类型的需求。
<a name="subscript_syntax"></a>
## 下标脚本语法
## 下标语法
下标脚本允许你通过在实例名称后面的方括号中传入一个或者多个索引值来对实例进行存取。语法类似于实例方法语法和计算型属性语法的混合。与定义实例方法类似,定义下标脚本使用`subscript`关键字,指定一个或多个入参和返回类型与实例方法不同的是,下标脚本可以设定为读写或只读。这种行为由 getter 和 setter 实现,有点类似计算型属性:
下标允许你通过在实例名称后面的方括号中传入一个或者多个索引值来对实例进行存取。语法类似于实例方法语法和计算型属性语法的混合。与定义实例方法类似,定义下标使用`subscript`关键字,指定一个或多个入参和返回类型与实例方法不同的是,下标可以设定为读写或只读。这种行为由 getter 和 setter 实现,有点类似计算型属性:
```swift
subscript(index: Int) -> Int {
@ -35,9 +39,9 @@ subscript(index: Int) -> Int {
}
```
`newValue`的类型和下标脚本的返回类型相同。如同计算型属性,可以不指定 setter 的参数(`newValue`。如果不指定参数setter 会提供一个名为`newValue`的默认参数。
`newValue`的类型和下标的返回类型相同。如同计算型属性,可以不指定 setter 的参数(`newValue`。如果不指定参数setter 会提供一个名为`newValue`的默认参数。
如同只读计算型属性,可以省略只读下标脚本`get`关键字:
如同只读计算型属性,可以省略只读下标的`get`关键字:
```swift
subscript(index: Int) -> Int {
@ -45,7 +49,7 @@ subscript(index: Int) -> Int {
}
```
下面代码演示了只读下标脚本的实现,这里定义了一个`TimesTable`结构体,用来表示传入整数的乘法表:
下面代码演示了只读下标的实现,这里定义了一个`TimesTable`结构体,用来表示传入整数的乘法表:
```swift
struct TimesTable {
@ -61,38 +65,38 @@ print("six times three is \(threeTimesTable[6])")
在上例中,创建了一个`TimesTable`实例,用来表示整数`3`的乘法表。数值`3`被传递给结构体的构造函数,作为实例成员`multiplier`的值。
你可以通过下标脚本访问`threeTimesTable`实例,例如上面演示的`threeTimesTable[6]`。这条语句查询了`3`的乘法表中的第六个元素,返回`3``6`倍即`18`
你可以通过下标访问`threeTimesTable`实例,例如上面演示的`threeTimesTable[6]`。这条语句查询了`3`的乘法表中的第六个元素,返回`3``6`倍即`18`
> 注意
> `TimesTable`例子基于一个固定的数学公式,对`threeTimesTable[someIndex]`进行赋值操作并不合适,因此下标脚本定义为只读的。
> `TimesTable`例子基于一个固定的数学公式,对`threeTimesTable[someIndex]`进行赋值操作并不合适,因此下标定义为只读的。
<a name="subscript_usage"></a>
## 下标脚本用法
## 下标用法
下标脚本的确切含义取决于使用场景。下标脚本通常作为访问集合collection列表list或序列sequence中元素的快捷方式。你可以针对自己特定的类或结构体的功能来自由地以最恰当的方式实现下标脚本
下标的确切含义取决于使用场景。下标通常作为访问集合collection列表list或序列sequence中元素的快捷方式。你可以针对自己特定的类或结构体的功能来自由地以最恰当的方式实现下标。
例如Swift 的`Dictionary`类型实现下标脚本用于对其实例中储存的值进行存取操作。为字典设值时,在下标脚本中使用和字典的键类型相同的键,并把一个和字典的值类型相同的值赋给这个下标脚本
例如Swift 的`Dictionary`类型实现下标用于对其实例中储存的值进行存取操作。为字典设值时,在下标中使用和字典的键类型相同的键,并把一个和字典的值类型相同的值赋给这个下标:
```swift
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
```
上例定义一个名为`numberOfLegs`的变量,并用一个包含三对键值的字典字面量初始化它。`numberOfLegs`字典的类型被推断为`[String: Int]`。字典创建完成后,该例子通过下标脚本`String`类型的键`bird``Int`类型的值`2`添加到字典中。
上例定义一个名为`numberOfLegs`的变量,并用一个包含三对键值的字典字面量初始化它。`numberOfLegs`字典的类型被推断为`[String: Int]`。字典创建完成后,该例子通过下标将`String`类型的键`bird``Int`类型的值`2`添加到字典中。
更多关于`Dictionary`下标脚本的信息请参考[读取和修改字典](./04_Collection_Types.html#accessing_and_modifying_a_dictionary)
更多关于`Dictionary`下标的信息请参考[读取和修改字典](./04_Collection_Types.html#accessing_and_modifying_a_dictionary)
> 注意
> Swift 的`Dictionary`类型的下标脚本接受并返回可选类型的值。上例中的`numberOfLegs`字典通过下标脚本返回的是一个`Int?`或者说“可选的int”。`Dictionary`类型之所以如此实现下标脚本,是因为不是每个键都有个对应的值,同时这也提供了一种通过键删除对应值的方式,只需将键对应的值赋值为`nil`即可。
> Swift 的`Dictionary`类型的下标接受并返回可选类型的值。上例中的`numberOfLegs`字典通过下标返回的是一个`Int?`或者说“可选的int”。`Dictionary`类型之所以如此实现下标,是因为不是每个键都有个对应的值,同时这也提供了一种通过键删除对应值的方式,只需将键对应的值赋值为`nil`即可。
<a name="subscript_options"></a>
## 下标脚本选项
## 下标选项
下标脚本可以接受任意数量的入参,并且这些入参可以是任意类型。下标脚本的返回值也可以是任意类型。下标脚本可以使用变量参数和可变参数,但不能使用输入输出参数,也不能给参数设置默认值。
下标可以接受任意数量的入参,并且这些入参可以是任意类型。下标的返回值也可以是任意类型。下标可以使用变量参数和可变参数,但不能使用输入输出参数,也不能给参数设置默认值。
一个类或结构体可以根据自身需要提供多个下标脚本实现,使用下标脚本时将通过入参的数量和类型进行区分,自动匹配合适的下标脚本,这就是*下标脚本的重载*。
一个类或结构体可以根据自身需要提供多个下标实现,使用下标时将通过入参的数量和类型进行区分,自动匹配合适的下标,这就是*下标的重载*。
虽然接受单一入参的下标脚本是最常见的,但也可以根据情况定义接受多个入参的下标脚本。例如下例定义了一个`Matrix`结构体,用于表示一个`Double`类型的二维矩阵。`Matrix`结构体的下标脚本接受两个整型参数:
虽然接受单一入参的下标是最常见的,但也可以根据情况定义接受多个入参的下标。例如下例定义了一个`Matrix`结构体,用于表示一个`Double`类型的二维矩阵。`Matrix`结构体的下标接受两个整型参数:
```swift
struct Matrix {
@ -131,18 +135,18 @@ var matrix = Matrix(rows: 2, columns: 2)
![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/subscriptMatrix01_2x.png)
`row``column`的值传入下标脚本来为矩阵设值,下标脚本的入参使用逗号分隔:
`row``column`的值传入下标来为矩阵设值,下标的入参使用逗号分隔:
```swift
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
```
上面两条语句分别调用下标脚本的 setter 将矩阵右上角位置(即`row``0``column``1`的位置)的值设置为`1.5`,将矩阵左下角位置(即`row``1``column``0`的位置)的值设置为`3.2`
上面两条语句分别调用下标的 setter 将矩阵右上角位置(即`row``0``column``1`的位置)的值设置为`1.5`,将矩阵左下角位置(即`row``1``column``0`的位置)的值设置为`3.2`
![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/subscriptMatrix02_2x.png)
`Matrix`下标脚本的 getter 和 setter 中都含有断言,用来检查下标脚本入参`row``column`的值是否有效。为了方便进行断言,`Matrix`包含了一个名为`indexIsValidForRow(_:column:)`的便利方法,用来检查入参`row``column`的值是否在矩阵范围内:
`Matrix`下标的 getter 和 setter 中都含有断言,用来检查下标入参`row``column`的值是否有效。为了方便进行断言,`Matrix`包含了一个名为`indexIsValidForRow(_:column:)`的便利方法,用来检查入参`row``column`的值是否在矩阵范围内:
```swift
func indexIsValidForRow(row: Int, column: Int) -> Bool {
@ -150,7 +154,7 @@ func indexIsValidForRow(row: Int, column: Int) -> Bool {
}
```
断言在下标脚本越界时触发:
断言在下标越界时触发:
```swift
let someValue = matrix[2, 2]

View File

@ -17,14 +17,14 @@
一个类可以*继承inherit*另一个类的方法methods属性properties和其它特性。当一个类继承其它类时继承类叫*子类subclass*,被继承类叫*超类或父类superclass*。在 Swift 中,继承是区分「类」与其它类型的一个基本特征。
在 Swift 中,类可以调用和访问超类的方法,属性和下标脚本subscripts并且可以重写override这些方法属性和下标脚本来优化或修改它们的行为。Swift 会检查你的重写定义在超类中是否有匹配的定义,以此确保你的重写行为是正确的。
在 Swift 中类可以调用和访问超类的方法属性和下标subscripts并且可以重写override这些方法属性和下标来优化或修改它们的行为。Swift 会检查你的重写定义在超类中是否有匹配的定义,以此确保你的重写行为是正确的。
可以为类中继承来的属性添加属性观察器property observers这样一来当属性值改变时类就会被通知到。可以为任何属性添加属性观察器无论它原本被定义为存储型属性stored property还是计算型属性computed property
<a name="defining_a_base_class"></a>
## 定义一个基类Base class
不继承于其它类的类,称之为*基类base calss*。
不继承于其它类的类,称之为*基类base class*。
> 注意
Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。
@ -124,21 +124,21 @@ print("Tandem: \(tandem.description)")
<a name="overriding"></a>
## 重写Overriding
子类可以为继承来的实例方法instance method类方法class method实例属性instance property或下标脚本subscript提供自己定制的实现implementation。我们把这种行为叫*重写overriding*。
子类可以为继承来的实例方法instance method类方法class method实例属性instance property或下标subscript提供自己定制的实现implementation。我们把这种行为叫*重写overriding*。
如果要重写某个特性,你需要在重写定义的前面加上`override`关键字。这么做,你就表明了你是想提供一个重写版本,而非错误地提供了一个相同的定义。意外的重写行为可能会导致不可预知的错误,任何缺少`override`关键字的重写都会在编译时被诊断为错误。
`override`关键字会提醒 Swift 编译器去检查该类的超类(或其中一个父类)是否有匹配重写版本的声明。这个检查可以确保你的重写定义是正确的。
### 访问超类的方法,属性及下标脚本
### 访问超类的方法,属性及下标
当你在子类中重写超类的方法,属性或下标脚本时,有时在你的重写版本中使用已经存在的超类实现会大有裨益。比如,你可以完善已有实现的行为,或在一个继承来的变量中存储一个修改过的值。
当你在子类中重写超类的方法,属性或下标时,有时在你的重写版本中使用已经存在的超类实现会大有裨益。比如,你可以完善已有实现的行为,或在一个继承来的变量中存储一个修改过的值。
在合适的地方,你可以通过使用`super`前缀来访问超类版本的方法,属性或下标脚本
在合适的地方,你可以通过使用`super`前缀来访问超类版本的方法,属性或下标:
* 在方法`someMethod()`的重写实现中,可以通过`super.someMethod()`来调用超类版本的`someMethod()`方法。
* 在属性`someProperty`的 getter 或 setter 的重写实现中,可以通过`super.someProperty`来访问超类版本的`someProperty`属性。
* 在下标脚本的重写实现中,可以通过`super[someIndex]`来访问超类版本中的相同下标脚本
* 在下标的重写实现中,可以通过`super[someIndex]`来访问超类版本中的相同下标。
### 重写方法
@ -231,8 +231,8 @@ print("AutomaticCar: \(automatic.description)")
<a name="preventing_overrides"></a>
## 防止重写
你可以通过把方法,属性或下标脚本标记为*`final`*来防止它们被重写,只需要在声明关键字前加上`final`修饰符即可(例如:`final var``final func``final class func`,以及`final subscript`)。
你可以通过把方法,属性或下标标记为*`final`*来防止它们被重写,只需要在声明关键字前加上`final`修饰符即可(例如:`final var``final func``final class func`,以及`final subscript`)。
如果你重写了`final`方法,属性或下标脚本,在编译时会报错。在类扩展中的方法,属性或下标脚本也可以在扩展的定义里标记为 final 的。
如果你重写了`final`方法,属性或下标,在编译时会报错。在类扩展中的方法,属性或下标也可以在扩展的定义里标记为 final 的。
你可以通过在关键字`class`前添加`final`修饰符(`final class`)来将整个类标记为 final 的。这样的类是不可被继承的,试图继承这样的类会导致编译报错。

View File

@ -9,8 +9,12 @@
> 翻译+校对:[chenmingbiao](https://github.com/chenmingbiao)
> 2.1
> 翻译:[Channe](https://github.com/Channe)
> 校对:[shanks](http://codebuild.me)2015-10-30
> 翻译:[Channe](https://github.com/Channe)[Realank](https://github.com/Realank)
> 校对:[shanks](http://codebuild.me)2016-1-23
> 2.2
> 翻译:[pmst](https://github.com/colourful987)
> 校对:[]()
本页包含内容:
@ -118,7 +122,7 @@ let freezingPointOfWater = Celsius(fromKelvin: 273.15)
跟函数和方法参数相同,构造参数也拥有一个在构造器内部使用的参数名字和一个在调用构造器时使用的外部参数名字。
然而构造器并不像函数和方法那样在括号前有一个可辨别的名字。因此在调用构造器时主要通过构造器中的参数名和类型来确定应该被调用的构造器。正因为参数如此重要如果你在定义构造器时没有提供参数的外部名字Swift 会为每个构造器的参数自动生成一个跟内部名字相同的外部名。
然而构造器并不像函数和方法那样在括号前有一个可辨别的名字。因此在调用构造器时主要通过构造器中的参数名和类型来确定应该被调用的构造器。正因为参数如此重要如果你在定义构造器时没有提供参数的外部名字Swift 会为构造器的每个参数自动生成一个跟内部名字相同的外部名。
以下例子中定义了一个结构体`Color`,它包含了三个常量:`red``green``blue`。这些属性可以存储`0.0``1.0`之间的值,用来指示颜色中红、绿、蓝成分的含量。
@ -183,7 +187,7 @@ let bodyTemperature = Celsius(37.0)
<a name="optional_property_types"></a>
### 可选属性类型
如果你定制的类型包含一个逻辑上允许取值为空的存储型属性——无论是因为它无法在初始化时赋值,还是因为它在之后某个时间点可以赋值为空——你都需要将它定义为可选类型`optional type`。可选类型的属性将自动初始化为`nil`,表示这个属性是有意在初始化时设置为空的。
如果你定制的类型包含一个逻辑上允许取值为空的存储型属性——无论是因为它无法在初始化时赋值,还是因为它在之后某个时间点可以赋值为空——你都需要将它定义为`可选类型`optional type。可选类型的属性将自动初始化为`nil`,表示这个属性是有意在初始化时设置为空的。
下面例子中定义了类`SurveyQuestion`,它包含一个可选字符串属性`response`
@ -204,12 +208,12 @@ cheeseQuestion.ask()
cheeseQuestion.response = "Yes, I do like cheese."
```
调查问题的答案在回答前是无法确定的,因此我们将属性`response`声明为`String?`类型,或者说是可选字符串类型`optional String`。当`SurveyQuestion`实例化时,它将自动赋值为`nil`,表明此字符串暂时还没有值。
调查问题的答案在回答前是无法确定的,因此我们将属性`response`声明为`String?`类型,或者说是`可选字符串类型`optional String。当`SurveyQuestion`实例化时,它将自动赋值为`nil`,表明此字符串暂时还没有值。
<a name="assigning_constant_properties_during_initialization"></a>
### 构造过程中常量属性的修改
你可以在构造过程中的任意时间点修改常量属性值,只要在构造过程结束时是一个确定的值。一旦常量属性被赋值,它将永远不可更改。
你可以在构造过程中的任意时间点常量属性指定一个值,只要在构造过程结束时是一个确定的值。一旦常量属性被赋值,它将永远不可更改。
> 注意
对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。
@ -236,7 +240,7 @@ beetsQuestion.response = "I also like beets. (But not with cheese.)"
<a name="default_initializers"></a>
## 默认构造器
如果结构体或类的所有属性都有默认值,同时没有自定义的构造器,那么 Swift 会给这些结构体或类提供一个默认构造器。这个默认构造器将简单地创建一个所有属性值都设置为默认值的实例。
如果结构体或类的所有属性都有默认值,同时没有自定义的构造器,那么 Swift 会给这些结构体或类提供一个默认构造器default initializers。这个默认构造器将简单地创建一个所有属性值都设置为默认值的实例。
下面例子中创建了一个类`ShoppingListItem`,它封装了购物清单中的某一物品的属性:名字(`name`)、数量(`quantity`)和购买状态 `purchase state`
@ -260,7 +264,7 @@ var item = ShoppingListItem()
下面例子中定义了一个结构体`Size`,它包含两个属性`width``height`。Swift 可以根据这两个属性的初始赋值`0.0`自动推导出它们的类型为`Double`
由于这两个存储型属性都有默认值,结构体`Size`自动获得了一个逐一成员构造器`init(width:height:)`。你可以用它来为`Size`创建新的实例:
结构体`Size`自动获得了一个逐一成员构造器`init(width:height:)`。你可以用它来为`Size`创建新的实例:
```swift
struct Size {
@ -270,11 +274,12 @@ let twoByTwo = Size(width: 2.0, height: 2.0)
```
<a name="initializer_delegation_for_value_types"></a>
## 值类型的构造器代理
构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能减少多个构造器间的代码重复。
构造器代理的实现规则和形式在值类型和类类型中有所不同。值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给提供给它的构造器。类则不同,它可以继承自其它类(请参考[继承](./13_Inheritance.html)),这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。这些责任将在后续章节[类的继承和构造过程](#class_inheritance_and_initialization)中介绍。
构造器代理的实现规则和形式在值类型和类类型中有所不同。值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给自己的其它构造器。类则不同,它可以继承自其它类(请参考[继承](./13_Inheritance.html)),这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。这些责任将在后续章节[类的继承和构造过程](#class_inheritance_and_initialization)中介绍。
对于值类型,你可以使用`self.init`在自定义的构造器中引用类型中的其它构造器。并且你只能在构造器内部调用`self.init`
@ -351,11 +356,11 @@ Swift 为类类型提供了两种构造器来确保实例中所有存储型属
<a name="designated_initializers_and_convenience_initializers"></a>
### 指定构造器和便利构造器
*指定构造器*是类中最主要的构造器。一个指定构造器将初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。
*指定构造器*designated initializers是类中最主要的构造器。一个指定构造器将初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。
每一个类都必须拥有至少一个指定构造器。在某些情况下,许多类通过继承了父类中的指定构造器而满足了这个条件。具体内容请参考后续章节[构造器的自动继承](#automatic_initializer_inheritance)。
*便利构造器*是类中比较次要的、辅助型的构造器。你可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值。你也可以定义便利构造器来创建一个特殊用途或特定输入值的实例。
*便利构造器*convenience initializers是类中比较次要的、辅助型的构造器。你可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值。你也可以定义便利构造器来创建一个特殊用途或特定输入值的实例。
你应当只在必要的时候为类提供便利构造器,比方说某种情况下通过使用便利构造器来快捷调用某个指定构造器,能够节省更多开发时间并让类的构造过程更清晰明了。
@ -415,14 +420,14 @@ convenience init(parameters) {
<a name="two_phase_initialization"></a>
### 两段式构造过程
Swift 中类的构造过程包含两个阶段。第一个阶段,每个存储型属性通过引入它们的类的构造器来设置初始值。当每个存储型属性值被确定后,第二阶段开始,它给每个类一次机会在新实例准备使用之前进一步定制它们的存储型属性。
Swift 中类的构造过程包含两个阶段。第一个阶段,每个存储型属性引入它们的类指定一个初始值。当每个存储型属性的初始值被确定后,第二阶段开始,它给每个类一次机会在新实例准备使用之前进一步定制它们的存储型属性。
两段式构造过程的使用让构造过程更安全,同时在整个类层级结构中给予了每个类完全的灵活性。两段式构造过程可以防止属性值在初始化之前被访问,也可以防止属性被另外一个构造器意外地赋予不同的值。
> 注意
Swift 的两段式构造过程跟 Objective-C 中的构造过程类似。最主要的区别在于阶段 1Objective-C 给每一个属性赋值`0`或空值(比如说`0``nil`。Swift 的构造流程则更加灵活,它允许你设置定制的初始值,并自如应对某些属性不能以`0``nil`作为合法默认值的情况。
Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造过程能顺利完成:
Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造过程能不出错地完成:
##### 安全检查 1
@ -494,7 +499,7 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造
当你在编写一个和父类中指定构造器相匹配的子类构造器时,你实际上是在重写父类的这个指定构造器。因此,你必须在定义子类构造器时带上`override`修饰符。即使你重写的是系统自动提供的默认构造器,也需要带上`override`修饰符,具体内容请参考[默认构造器](#default_initializers)。
正如重写属性,方法或者是下标脚本`override`修饰符会让编译器去检查父类中是否有相匹配的指定构造器,并验证构造器参数是否正确。
正如重写属性,方法或者是下标,`override`修饰符会让编译器去检查父类中是否有相匹配的指定构造器,并验证构造器参数是否正确。
> 注意
当你重写一个父类的指定构造器时,你总是需要写`override`修饰符,即使你的子类将父类的指定构造器重写为了便利构造器。
@ -559,7 +564,7 @@ print("Bicycle: \(bicycle.description)")
##### 规则 2
如果子类提供了所有父类指定构造器的实现——无论是通过规则 1 继承过来的,还是提供了自定义实现——它将自动继承所有父类的便利构造器。(即使属性没有默认值,只要实现了父类的所有指定构造器,就会自动继承父类的所有便利构造器)
如果子类提供了所有父类指定构造器的实现——无论是通过规则 1 继承过来的,还是提供了自定义实现——它将自动继承所有父类的便利构造器。
即使你在子类中添加了更多的便利构造器,这两条规则仍然适用。
@ -691,7 +696,7 @@ for item in breakfastList {
如果一个类、结构体或枚举类型的对象,在构造过程中有可能失败,则为其定义一个可失败构造器。这里所指的“失败”是指,如给构造器传入无效的参数值,或缺少某种所需的外部资源,又或是不满足某种必要的条件等。
为了妥善处理这种构造过程中可能会失败的情况。你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在`init`关键字后面添问号`(init?)`
为了妥善处理这种构造过程中可能会失败的情况。你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在`init`关键字后面添问号(`init?`)
> 注意
可失败构造器的参数名和参数类型,不能与其它非可失败构造器的参数名,及其参数类型相同。
@ -806,44 +811,6 @@ if unknownUnit == nil {
// 打印 "This is not a defined temperature unit, so initialization failed."
```
<a name="failable_initializers_for_classes"></a>
### 类的可失败构造器
值类型(也就是结构体或枚举)的可失败构造器,可以在构造过程中的任意时间点触发构造失败。比如在前面的例子中,结构体`Animal`的可失败构造器在构造过程一开始就触发了构造失败,甚至在`species`属性被初始化前。
而对类而言,可失败构造器只能在类引入的所有存储型属性被初始化后,以及构造器代理调用完成后,才能触发构造失败。
下面例子展示了如何在类的可失败构造器中使用隐式解包可选类型来满足上述要求:
```swift
class Product {
let name: String!
init?(name: String) {
self.name = name
if name.isEmpty { return nil }
}
}
```
上面定义的`Product`类和之前的`Animal`结构体很相似。`Product`类有一个不能为空字符串的常量属性`name`。为了强制这个要求,`Product`类使用了可失败构造器确保这个属性的值不是空字符串后,才允许构造成功。
毕竟,`Product`是一个类而不是结构体,这意味着不同于`Animal``Product`类的所有可失败构造器必须给`name`属性一个初始值,然后才能触发构造失败。
上面的例子中,`Product`类的`name`属性被定义为隐式解包可选字符串类型(`String!`)。因为它是一个可选类型,所以它在构造过程中被赋值前,具有默认值`nil`。这个默认值`nil`意味着`Product`类引入的所有存储型属性都有一个有效的初始值。因此,一旦传入一个空字符串,该可失败构造器可以在`name`属性被赋值前触发构造失败。
> 译者注
> 上面的示例代码和描述并不相符,根据描述,`if name.isEmpty { return nil }`这句代码应该在`self.name = name`之前,而这却会导致编译错误`error: all stored properties of a class instance must be initialized before returning nil from an initializer`,除非将`let name: String!`改为`var name: String!`。
因为`name`属性是一个常量,所以一旦构造成功,`name`属性肯定有一个非`nil`的值。即使它被定义为隐式解包可选类型,也完全可以放心大胆地直接访问,而不用检查`name`属性的值是否为`nil`
```swift
if let bowTie = Product(name: "bow tie") {
// 不需要检查 bowTie.name 是否为 nil
print("The product's name is \(bowTie.name)")
}
// 打印 "The product's name is bow tie"
```
<a name="propagation_of_initialization_failure"></a>
### 构造失败的传递
@ -856,36 +823,38 @@ if let bowTie = Product(name: "bow tie") {
下面这个例子,定义了一个名为`CartItem``Product`类的子类。这个类建立了一个在线购物车中的物品的模型,它有一个名为`quantity`的常量存储型属性,并确保该属性的值至少为`1`
```swift
class Product {
let name: String
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
class CartItem: Product {
let quantity: Int!
let quantity: Int
init?(name: String, quantity: Int) {
if quantity < 1 { return nil }
self.quantity = quantity
super.init(name: name)
if quantity < 1 { return nil }
}
}
```
`Product`类中的`name`属性类似,`CartItem`类中的`quantity`属性也是隐式解包可选类型。这意味着在构造过程中,该属性在被赋予特定的值之前能有一个默认的初始值`nil`
`CartItem` 可失败构造器首先验证接收的 `quantity` 值是否大于等于 1 。倘若 `quantity` 值无效,则立即终止整个构造过程,返回失败结果,且不再执行余下代码。同样地,`Product` 的可失败构造器首先检查 `name` 值,假如 `name` 值为空字符串,则构造器立即执行失败
该可失败构造器以向上代理到父类的可失败构造器`init(name:)`开始。这满足了可失败构造器在触发构造失败前必须总是完成构造器代理调用这个条件。
如果由于`name`的值为空字符串而导致父类的可失败构造器构造失败,则`CartIem`类的整个构造过程都将立即失败,之后的构造代码将不会再被执行。如果父类构造成功,`CartIem`的可失败构造器会进一步验证`quantity`的值是否不小于`1`
> 译者注
> 上面的示例代码和描述也不相符,根据描述,`self.quantity = quantity`这句代码应该放在最后一行,而这却会导致编译错误`error: property 'self.quantity' not initialized at super.init call`,除非将`let quantity: Int!`改为`var quantity: Int!`。
如果你构造一个`name`的值为非空字符串,`quantity`的值不小于`1``CartItem`实例,则可成功构造:
如果你通过传入一个非空字符串 `name` 以及一个值大于等于 1 的 `quantity` 来创建一个 `CartItem` 实例,那么构造方法能够成功被执行:
```swift
if let twoSocks = CartItem(name: "sock", quantity: 2) {
print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
}
// 打印 "Item: sock, quantity: 2"
// 打印 "Item: sock, quantity: 2
```
如果你试图构造一个`quantity`的值为`0``CartItem`实例, 则`CartItem`的可失败构造器会触发构造失败:
倘若你以一个值为 0 的 `quantity` 来创建一个 `CartItem` 实例,那么将导致 `CartItem` 构造器失败:
```swift
if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
@ -893,10 +862,10 @@ if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
} else {
print("Unable to initialize zero shirts")
}
// 打印 "Unable to initialize zero shirts"
```
// 打印 "Unable to initialize zero shirts
```
类似的,如果你试图构造一个`name`的值为空字符串的`CartItem`实例,则父类`Product`的可失败构造器会触发构造失败:
同样地,如果你尝试传入一个值为空字符串的 `name`来创建一个 `CartItem` 实例,那么将导致父类 `Product` 的构造过程失败:
```swift
if let oneUnnamed = CartItem(name: "", quantity: 1) {
@ -904,7 +873,7 @@ if let oneUnnamed = CartItem(name: "", quantity: 1) {
} else {
print("Unable to initialize one unnamed product")
}
// 打印 "Unable to initialize one unnamed product"
// 打印 "Unable to initialize one unnamed product
```
<a name="overriding_a_failable_initializer"></a>

View File

@ -10,7 +10,7 @@
> 2.1
> 翻译:[Channe](https://github.com/Channe)
> 校对:[shanks](http://codebuild.me)2015-10-31
> 校对:[shanks](http://codebuild.me)[Realank](https://github.com/Realank) 2016-01-23
本页包含内容:
@ -23,7 +23,7 @@
Swift 使用自动引用计数ARC机制来跟踪和管理你的应用程序的内存。通常情况下Swift 内存管理机制会一直起作用你无须自己来考虑内存的管理。ARC 会在类的实例不再被使用时,自动释放其占用的内存。
然而在少数情况下,ARC 为了能帮助你管理内存,需要更多的关于你的代码之间关系的信息。本章描述了这些情况,并且为你示范怎样启用 ARC 来管理你的应用程序的内存。
然而在少数情况下,为了能帮助你管理内存,ARC 需要更多的代码之间关系的信息。本章描述了这些情况,并且为你示范怎样才能使 ARC 来管理你的应用程序的所有内存。
> 注意
引用计数仅仅应用于类的实例。结构体和枚举类型是值类型,不是引用类型,也不是通过引用的方式存储和传递。
@ -31,7 +31,7 @@ Swift 使用自动引用计数ARC机制来跟踪和管理你的应用程
<a name="how_arc_works"></a>
## 自动引用计数的工作机制
当你每次创建一个类的新的实例的时候ARC 会分配一块内存来储存实例信息。内存中会包含实例的类型信息,以及这个实例所有相关属性的值。
当你每次创建一个类的新的实例的时候ARC 会分配一块内存来储存实例信息。内存中会包含实例的类型信息,以及这个实例所有相关的存储型属性的值。
此外当实例不再被使用时ARC 释放实例所占用的内存,并让释放的内存能挪作他用。这确保了不再被使用的实例,不会一直占用内存空间。
@ -134,7 +134,7 @@ class Apartment {
每一个`Person`实例有一个类型为`String`,名字为`name`的属性,并有一个可选的初始化为`nil``apartment`属性。`apartment`属性是可选的,因为一个人并不总是拥有公寓。
类似的,每个`Apartment`实例有一个叫`number`,类型为`Int`的属性,并有一个可选的初始化为`nil``tenant`属性。`tenant`属性是可选的,因为一栋公寓并不总是有居民。
类似的,每个`Apartment`实例有一个叫`unit`,类型为`String`的属性,并有一个可选的初始化为`nil``tenant`属性。`tenant`属性是可选的,因为一栋公寓并不总是有居民。
这两个类都定义了析构函数,用以在类实例被析构的时候输出信息。这让你能够知晓`Person``Apartment`的实例是否像预期的那样被销毁。
@ -411,7 +411,7 @@ print("\(country.name)'s capital city is called \(country.capitalCity.name)")
循环强引用的产生,是因为闭包和类相似,都是引用类型。当你把一个闭包赋值给某个属性时,你是将这个闭包的引用赋值给了属性。实质上,这跟之前的问题是一样的——两个强引用让彼此一直有效。但是,和两个类实例不同,这次一个是类实例,另一个是闭包。
Swift 提供了一种优雅的方法来解决这个问题称之为闭包捕获列表closuer capture list。同样的在学习如何用闭包捕获列表破循环强引用之前,先来了解一下这里的循环强引用是如何产生的,这对我们很有帮助。
Swift 提供了一种优雅的方法来解决这个问题,称之为`闭包捕获列表`closure capture list。同样的在学习如何用闭包捕获列表破循环强引用之前,先来了解一下这里的循环强引用是如何产生的,这对我们很有帮助。
下面的例子为你展示了当一个闭包引用了`self`后是如何产生一个循环强引用的。例子中定义了一个叫`HTMLElement`的类,用一种简单的模型表示 HTML 文档中的一个单独的元素:
@ -471,7 +471,7 @@ print(heading.asHTML())
```swift
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
// 打印 “hello, world”
// 打印 “<p>hello, world</p>
```
> 注意
@ -528,9 +528,9 @@ lazy var someClosure: Void -> String = {
<a name="weak_and_unowned_references"></a>
###弱引用和无主引用
在闭包和捕获的实例总是互相引用并且总是同时销毁时,将闭包内的捕获定义为无主引用。
在闭包和捕获的实例总是互相引用并且总是同时销毁时,将闭包内的捕获定义为`无主引用`
相反的,在被捕获的引用可能会变为`nil`时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为`nil`。这使我们可以在闭包体内检查它们是否存在。
相反的,在被捕获的引用可能会变为`nil`时,将闭包内的捕获定义为`弱引用`。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为`nil`。这使我们可以在闭包体内检查它们是否存在。
> 注意
如果被捕获的引用绝对不会变为`nil`,应该用无主引用,而不是弱引用。

View File

@ -65,11 +65,11 @@ class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
<a name="property_requirements"></a>
## 属性要求
协议可以要求采纳协议的类型提供特定名称和类型的实例属性或类型属性。协议不指定属性是存储型属性还是计算型属性,它只指定属性的名称和类型。此外,协议还指定属性是读的还是可读可写的。
协议可以要求采纳协议的类型提供特定名称和类型的实例属性或类型属性。协议不指定属性是存储型属性还是计算型属性,它只指定属性的名称和类型。此外,协议还指定属性是读的还是可读可写的。
如果协议要求属性是可读可写的,那么该属性不能是常量属性或只读的计算型属性。如果协议只要求属性是读的,那么该属性不仅可以是读的,如果代码需要的话,还可以是可写的。
如果协议要求属性是可读可写的,那么该属性不能是常量属性或只读的计算型属性。如果协议只要求属性是读的,那么该属性不仅可以是读的,如果代码需要的话,还可以是可写的。
协议通常`var` 关键字来声明变量属性,在类型声明后加上 `{ set get }` 来表示属性是可读可写的,读属性则用 `{ get }` 来表示:
协议总是`var` 关键字来声明变量属性,在类型声明后加上 `{ set get }` 来表示属性是可读可写的,读属性则用 `{ get }` 来表示:
```swift
protocol SomeProtocol {
@ -94,7 +94,7 @@ protocol FullyNamed {
}
```
`FullyNamed` 协议除了要求采纳协议的类型提供 `fullName` 属性外,并没有其他特别的要求。这个协议表示,任何采纳 `FullyNamed` 的类型,都必须有一个读的 `String` 类型的实例属性 `fullName`
`FullyNamed` 协议除了要求采纳协议的类型提供 `fullName` 属性外,并没有其他特别的要求。这个协议表示,任何采纳 `FullyNamed` 的类型,都必须有一个读的 `String` 类型的实例属性 `fullName`
下面是一个采纳 `FullyNamed` 协议的简单结构体:
@ -155,7 +155,7 @@ protocol RandomNumberGenerator {
`RandomNumberGenerator` 协议并不关心每一个随机数是怎样生成的,它只要求必须提供一个随机数生成器。
如下所示,下边是一个采纳 `RandomNumberGenerator` 协议的类。该类实现了一个叫做 *线性同余生成器linear congruential generator* 的伪随机数算法。
如下所示,下边是一个采纳并符合 `RandomNumberGenerator` 协议的类。该类实现了一个叫做 *线性同余生成器linear congruential generator* 的伪随机数算法。
```swift
class LinearCongruentialGenerator: RandomNumberGenerator {
@ -385,7 +385,7 @@ class SnakesAndLadders: DiceGame {
关于这个蛇梯棋游戏的详细描述请参阅 [Control Flow](./05_Control_Flow.html) 章节中的 [Break](./05_Control_Flow.html#break) 部分。
这个版本的游戏封装到了 `SnakesAndLadders` 类中,该类采纳了 `DiceGame` 协议,并且提供了相应的读的 `dice` 属性和 `play()` 方法。( `dice` 属性在构造之后就不再改变,且协议只要求 `dice`读的,因此将 `dice` 声明为常量属性。)
这个版本的游戏封装到了 `SnakesAndLadders` 类中,该类采纳了 `DiceGame` 协议,并且提供了相应的读的 `dice` 属性和 `play()` 方法。( `dice` 属性在构造之后就不再改变,且协议只要求 `dice`读的,因此将 `dice` 声明为常量属性。)
游戏使用 `SnakesAndLadders` 类的 `init()` 构造器来初始化游戏。所有的游戏逻辑被转移到了协议中的 `play()` 方法,`play()` 方法使用协议要求的 `dice` 属性提供骰子摇出的值。
@ -442,7 +442,7 @@ game.play()
<a name="adding_protocol_conformance_with_an_extension"></a>
## 通过扩展添加协议一致性
即便无法修改源代码,依然可以通过扩展令已有类型采纳并符合协议。扩展可以为已有类型添加属性、方法、下标脚本以及构造器,因此可以符合协议中的相应要求。详情请在[扩展](./21_Extensions.html)章节中查看。
即便无法修改源代码,依然可以通过扩展令已有类型采纳并符合协议。扩展可以为已有类型添加属性、方法、下标以及构造器,因此可以符合协议中的相应要求。详情请在[扩展](./21_Extensions.html)章节中查看。
> 注意
> 通过扩展令已有类型采纳并符合协议时,该类型的所有实例也会随之获得协议中定义的各项功能。
@ -470,8 +470,8 @@ extension Dice: TextRepresentable {
现在所有 `Dice` 的实例都可以看做 `TextRepresentable` 类型:
```swift
let d12 = Dice(sides: 12,generator: LinearCongruentialGenerator())
print(d12. textualDescription)
let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())
print(d12.textualDescription)
// 打印 “A 12-sided dice”
```
@ -652,7 +652,7 @@ wishHappyBirthday(birthdayPerson)
* `as?` 返回一个可选值,当实例符合某个协议时,返回类型为协议类型的可选值,否则返回 `nil`
* `as!` 将实例强制向下转换到某个协议类型,如果强转失败,会引发运行时错误。
下面的例子定义了一个 `HasArea` 协议,该协议定义了一个 `Double` 类型的读属性 `area`
下面的例子定义了一个 `HasArea` 协议,该协议定义了一个 `Double` 类型的读属性 `area`
```swift
protocol HasArea {
@ -834,7 +834,7 @@ for _ in 1...5 {
<a name="protocol_extensions"></a>
## 协议扩展
协议可以通过扩展来为采纳协议的类型提供属性、方法以及下标脚本的实现。通过这种方式,你可以基于协议本身来实现这些功能,而无需在每个采纳协议的类型中都重复同样的实现,也无需使用全局函数。
协议可以通过扩展来为采纳协议的类型提供属性、方法以及下标的实现。通过这种方式,你可以基于协议本身来实现这些功能,而无需在每个采纳协议的类型中都重复同样的实现,也无需使用全局函数。
例如,可以扩展 `RandomNumberGenerator` 协议来提供 `randomBool()` 方法。该方法使用协议中定义的 `random()` 方法来返回一个随机的 `Bool` 值:
@ -859,7 +859,7 @@ print("And here's a random Boolean: \(generator.randomBool())")
<a name="providing_default_implementations"></a>
### 提供默认实现
可以通过协议扩展来为协议要求的属性、方法以及下标脚本提供默认的实现。如果采纳协议的类型为这些要求提供了自己的实现,那么这些自定义实现将会替代扩展中的默认实现被使用。
可以通过协议扩展来为协议要求的属性、方法以及下标提供默认的实现。如果采纳协议的类型为这些要求提供了自己的实现,那么这些自定义实现将会替代扩展中的默认实现被使用。
> 注意
> 通过协议扩展为协议要求提供的默认实现和可选的协议要求不同。虽然在这两种情况下,采纳协议的类型都无需自己实现这些要求,但是通过扩展提供的默认实现可以直接调用,而无需使用可选链式调用。
@ -877,7 +877,7 @@ extension PrettyTextRepresentable {
<a name="adding_constraints_to_protocol_extensions"></a>
### 为协议扩展添加限制条件
在扩展协议的时候,可以指定一些限制条件,只有采纳协议的类型满足这些限制条件时,才能获得协议扩展提供的默认实现。这些限制条件写在协议名之后,使用 `where` 子句来描述,正如[Where子句](./23_Generics.html#where_clauses))中所描述的。
在扩展协议的时候,可以指定一些限制条件,只有采纳协议的类型满足这些限制条件时,才能获得协议扩展提供的默认实现。这些限制条件写在协议名之后,使用 `where` 子句来描述,正如[Where子句](./23_Generics.html#where_clauses)中所描述的。
例如,你可以扩展 `CollectionType` 协议,但是只适用于集合中的元素采纳了 `TextRepresentable` 协议的情况:

View File

@ -12,6 +12,8 @@
> 2.1
> 校对:[shanks](http://codebuild.me)2015-11-01
> 2.2:翻译+校对:[Lanford](https://github.com/LanfordCai)2016-04-08
本页包含内容:
- [泛型所解决的问题](#the_problem_that_generics_solve)
@ -24,9 +26,9 @@
- [关联类型](#associated_types)
- [Where 子句](#where_clauses)
泛型代码可以让你编写适用自定义需求以及任意类型灵活可重用的函数类型。它的可以让你避免重复的代码,用一种清晰和抽象的方式来表达代码的意图。
泛型代码让你能够根据自定义需求,编写出适用于任意类型灵活可重用的函数类型。它让你避免代码的重复,用一种清晰和抽象的方式来表达代码的意图。
泛型是 Swift 强大特性之一,许多 Swift 标准库是通过泛型代码构建的。事实上泛型的使用贯穿了整本语言手册只是你可能没有发现而已。例如Swift 的 `Array``Dictionary` 都是泛型集合。你可以创建一个 `Int` 数组,也可创建一个 `String` 数组,甚至可以是任意其他 Swift 类型的数组。同样的,你也可以创建存储任意指定类型的字典。
泛型是 Swift 强大特性之一,许多 Swift 标准库是通过泛型代码构建的。事实上泛型的使用贯穿了整本语言手册只是你可能没有发现而已。例如Swift 的 `Array``Dictionary` 都是泛型集合。你可以创建一个 `Int` 数组,也可创建一个 `String` 数组,甚至可以是任意其他 Swift 类型的数组。同样的,你也可以创建存储任意指定类型的字典。
<a name="the_problem_that_generics_solve"></a>
## 泛型所解决的问题
@ -96,11 +98,11 @@ func swapTwoInts(inout a: Int, inout _ b: Int)
func swapTwoValues<T>(inout a: T, inout _ b: T)
```
这个函数的泛型版本使用了占位类型名(在这里用字母 `T` 来表示)来代替实际类型名(例如 `Int``String``Double`)。占位类型名没有指明 `T` 必须是什么类型,但是它指明了 `a``b` 必须是同一类型 `T`无论 `T` 代表什么类型。只有 `swapTwoValues(_:_:)` 函数在调用时,才能根据所传入的实际类型决定 `T` 所代表的类型。
这个函数的泛型版本使用了占位类型名(在这里用字母 `T` 来表示)来代替实际类型名(例如 `Int``String``Double`)。占位类型名没有指明 `T` 必须是什么类型,但是它指明了 `a``b` 必须是同一类型 `T`,无论 `T` 代表什么类型。只有 `swapTwoValues(_:_:)` 函数在调用时,才能根据所传入的实际类型决定 `T` 所代表的类型。
另外一个不同之处在于这个泛型函数名后面跟着占位类型名(`T`而且是用尖括号括起来`<T>`)。这个尖括号告诉 Swift 那个 `T``swapTwoValues(_:_:)` 函数定义的一个占位类型名,因此 Swift 不会去查找名为 `T` 的实际类型。
另外一个不同之处在于这个泛型函数名`swapTwoValues(_:_:)`后面跟着占位类型名(`T`用尖括号括起来(`<T>`)。这个尖括号告诉 Swift 那个 `T``swapTwoValues(_:_:)` 函数定义的一个占位类型名,因此 Swift 不会去查找名为 `T` 的实际类型。
`swapTwoValues(_:_:)` 函数现在可以像 `swapTwoInts(_:_:)` 那样调用,可以传入任意类型的值,只要两个值的类型相同`swapTwoValues(_:_:)` 函数被调用时,`T` 所代表的类型都会由传入的值的类型推断出来。
`swapTwoValues(_:_:)` 函数现在可以像 `swapTwoInts(_:_:)` 那样调用,不同的是它能接受两个任意类型的值,条件是这两个值有着相同的类型。`swapTwoValues(_:_:)` 函数被调用时,`T` 所代表的类型都会由传入的值的类型推断出来。
在下面的两个例子中,`T` 分别代表 `Int``String`
@ -131,22 +133,22 @@ swapTwoValues(&someString, &anotherString)
<a name="naming_type_parameters"></a>
## 命名类型参数
在大多数情况下,类型参数具有一个描述性名字,例如 `Dictionary<Key, Value>` 中的 `Key``Value`,以及 `Array<Element>` 中的 `Element`,这可以告诉阅读代码的人这些类型参数和泛型函数之间的关系。然而,当它们之间的关系没有意义时,通常使用单一的字母来命名,例如 `T``U``V`,正如上面演示的 `swapTwoValues(_:_:)` 函数中的 `T` 一样。
在大多数情况下,类型参数具有一个描述性名字,例如 `Dictionary<Key, Value>` 中的 `Key``Value`,以及 `Array<Element>` 中的 `Element`,这可以告诉阅读代码的人这些类型参数和泛型函数之间的关系。然而,当它们之间没有意义的关系时,通常使用单字母来命名,例如 `T``U``V`,正如上面演示的 `swapTwoValues(_:_:)` 函数中的 `T` 一样。
> 注意
请始终使用大写字母开头的驼峰命名法(例如 `T``MyTypeParameter`)来为类型参数命名,以表明它们是占位类型,而不是一个值。
请始终使用大写字母开头的驼峰命名法(例如 `T``MyTypeParameter`)来为类型参数命名,以表明它们是占位类型,而不是一个值。
<a name="generic_types"></a>
## 泛型类型
除了泛型函数Swift 还允许你定义泛型类型。这些自定义类、结构体和枚举可以适用于任何类型,如同 `Array``Dictionary` 的用法
除了泛型函数Swift 还允许你定义泛型类型。这些自定义类、结构体和枚举可以适用于任何类型,类似于 `Array``Dictionary`
这部分内容将向你展示如何编写一个名为 `Stack` (栈)的泛型集合类型。栈是一系列值的有序集合,和 `Array` 类似,但它相比 Swift 的 `Array` 类型有更多的操作限制。数组允许对其中任意位置的元素执行插入或删除操作。而栈只允许在集合的末端添加新的元素(称之为入栈)。同样的,栈也只能从末端移除元素(称之为出栈)。
这部分内容将向你展示如何编写一个名为 `Stack` (栈)的泛型集合类型。栈是一系列值的有序集合,和 `Array` 类似,但它相比 Swift 的 `Array` 类型有更多的操作限制。数组允许在数组的任意位置插入新元素或是删除其中任意位置的元素。而栈只允许在集合的末端添加新的元素(称之为入栈)。类似的,栈也只能从末端移除元素(称之为出栈)。
> 注意
栈的概念已被 `UINavigationController` 类用来模拟视图控制器的导航结构。你通过调用 `UINavigationController``pushViewController(_:animated:)` 方法来添加新的视图控制器到导航栈,通过 `popViewControllerAnimated(_:)` 方法来从导航栈中移除某个视图控制器。每当你需要一个严格的“后进先出”方式来管理集合,栈都是最实用的模型。
栈的概念已被 `UINavigationController` 类用来构造视图控制器的导航结构。你通过调用 `UINavigationController``pushViewController(_:animated:)` 方法来添加新的视图控制器到导航栈,通过 `popViewControllerAnimated(_:)` 方法来从导航栈中移除视图控制器。每当你需要一个严格的“后进先出”方式来管理集合,栈都是最实用的模型。
下图展示了一个栈的push和出栈pop的行为
下图展示了一个栈的push和出栈pop的行为
![此处输入图片的描述](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/stackPushPop_2x.png)
@ -154,9 +156,9 @@ swapTwoValues(&someString, &anotherString)
2. 第四个值被压入到栈的顶部。
3. 现在有四个值在栈中,最近入栈的那个值在顶部。
4. 栈中最顶部的那个值被移除,或称之为出栈。
5. 移除掉一个值后,现在栈再一次只有三个值。
5. 移除掉一个值后,现在栈只有三个值
下面展示了如何编写一个非泛型版本的栈,在这种情况下是 `Int` 型的栈:
下面展示了如何编写一个非泛型版本的栈, `Int` 型的栈为例
```swift
struct IntStack {
@ -188,15 +190,15 @@ struct Stack<Element> {
}
```
注意,`Stack` 基本上和 `IntStack` 相同,只是用占位类型参数 `Element` 代替了实际的 `Int` 类型。这类型参数包裹在一对尖括号里(`<Element>`,紧跟在结构体名后面
注意,`Stack` 基本上和 `IntStack` 相同,只是用占位类型参数 `Element` 代替了实际的 `Int` 类型。这类型参数包裹在紧随结构体名的一对尖括号里(`<Element>`)。
`Element`尚未提供的类型定义了一个占位名。这种尚未提供的类型可以在结构体的定义中通过 `Element` 来引用。在这种情况下`Element` 在如下三个地方被用作占位符:
`Element`提供的类型定义了一个占位名。这种提供的类型可以在结构体的定义中通过 `Element` 来引用。在这个例子中`Element` 在如下三个地方被用作占位符:
- 创建 `items` 属性,使用 `Element` 类型的空数组对其进行初始化。
- 指定 `push(_:)` 方法的一参数 `item` 的类型必须是 `Element` 类型。
- 指定 `push(_:)` 方法的一参数 `item` 的类型必须是 `Element` 类型。
- 指定 `pop()` 方法的返回值类型必须是 `Element` 类型。
由于 `Stack` 是泛型类型,因此可以用来创建 Swift 中任意有效类型的栈,如同 `Array``Dictionary`
由于 `Stack` 是泛型类型,因此可以用来创建 Swift 中任意有效类型的栈,就像 `Array``Dictionary` 那样
你可以通过在尖括号中写出栈中需要存储的数据类型来创建并初始化一个 `Stack` 实例。例如,要创建一个 `String` 类型的栈,可以写成 `Stack<String>()`
@ -227,7 +229,7 @@ let fromTheTop = stackOfStrings.pop()
<a name="extending_a_generic_type"></a>
## 扩展一个泛型类型
当你扩展一个泛型类型的时候,你并不需要在扩展的定义中提供类型参数列表。更加方便的是,原始类型定义中声明的类型参数列表在扩展中可以直接使用,并且这些来自原始类型中的参数名称会被用作原始定义中类型参数的引用。
当你扩展一个泛型类型的时候,你并不需要在扩展的定义中提供类型参数列表。原始类型定义中声明的类型参数列表在扩展中可以直接使用,并且这些来自原始类型中的参数名称会被用作原始定义中类型参数的引用。
下面的例子扩展了泛型类型 `Stack`,为其添加了一个名为 `topItem` 的只读计算型属性,它将会返回当前栈顶端的元素而不会将其从栈中移除:
@ -243,7 +245,7 @@ extension Stack {
注意,这个扩展并没有定义一个类型参数列表。相反的,`Stack` 类型已有的类型参数名称 `Element`,被用在扩展中来表示计算型属性 `topItem` 的可选类型。
计算型属性 `topItem` 现在可以用来访问任意 `Stack` 实例的顶端元素而不是移除它:
计算型属性 `topItem` 现在可以用来访问任意 `Stack` 实例的顶端元素且不移除它:
```swift
if let topItem = stackOfStrings.topItem {
@ -255,18 +257,18 @@ if let topItem = stackOfStrings.topItem {
<a name="type_constraints"></a>
## 类型约束
`swapTwoValues(_:_:)` 函数和 `Stack` 类型可以作用于任何类型。不过,有的时候如果能将使用在泛型函数和泛型类型中的类型,强制约束为某种特定类型,将会是非常有用的。类型约束可以指定一个类型参数必须继承自指定类,或者符合一个特定的协议或协议组合。
`swapTwoValues(_:_:)` 函数和 `Stack` 类型可以作用于任何类型。不过,有的时候如果能将使用在泛型函数和泛型类型中的类型添加一个特定类型约束,将会是非常有用的。类型约束可以指定一个类型参数必须继承自指定类,或者符合一个特定的协议或协议组合。
例如Swift 的 `Dictionary` 类型对字典的键的类型做了些限制。在[字典](./04_Collection_Types.html#dictionaries)的描述中,字典的键的类型必须是可哈希的。也就是说,必须有一种方法能作为其唯一表示。`Dictionary` 之所以需要其键是可哈希的,是为了便于检查字典是否已经包含某个特定键的值。如无此要求,`Dictionary` 将无法判断是否可以插入或者替换某个指定键的值,也不能查找到已经存储在字典中的指定键的值。
例如Swift 的 `Dictionary` 类型对字典的键的类型做了些限制。在[字典](./04_Collection_Types.html#dictionaries)的描述中,字典的键的类型必须是可哈希`hashable`的。也就是说,必须有一种方法能唯一表示`Dictionary` 的键之所以是可哈希的,是为了便于检查字典是否已经包含某个特定键的值。若没有这个要求,`Dictionary` 将无法判断是否可以插入或者替换某个指定键的值,也不能查找到已经存储在字典中的指定键的值。
这个要求强制加上了一个类型约束作用于 `Dictionary` 的键类型上,其键类型必须符合 `Hashable` 协议,这是 Swift 标准库中定义的一个特定协议。所有的 Swift 基本类型(例如 `String``Int``Double``Bool`)默认都是可哈希的。
为了实现这个要求,一个类型约束被强制加到 `Dictionary` 的键类型上,要求其键类型必须符合 `Hashable` 协议,这是 Swift 标准库中定义的一个特定协议。所有的 Swift 基本类型(例如 `String``Int``Double``Bool`)默认都是可哈希的。
当你创建自定义泛型类型时,你可以定义你自己的类型约束,这些约束将提供更为强大的泛型编程能力。抽象概念,例如可哈希的,描述的是类型在概念上的特征,而不是它们的显式类型。
<a name="type_constraint_syntax"></a>
### 类型约束语法
你可以在一个类型参数名后面放置一个类名或者协议名,通过冒号分隔,从而定义类型约束,它们将为类型参数列表的一部分。这种基本的类型约束作用于泛型函数时的语法如下所示(作用于泛型类型时的语法与之相同):
你可以在一个类型参数名后面放置一个类名或者协议名,并用冒号进行分隔,定义类型约束,它们将为类型参数列表的一部分。对泛型函数添加类型约束的基本语法如下所示(作用于泛型类型时的语法与之相同):
```swift
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
@ -279,7 +281,7 @@ func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
<a name="type_constraints_in_action"></a>
### 类型约束实践
这里有个名为 `findStringIndex` 的非泛型函数,该函数的功能是在 `String` 值的数组中查找给定 `String` 值的索引。若查找到匹配的字符串,`findStringIndex(_:_:)` 函数返回该字符串在数组中的索引值,反之则返回 `nil`
这里有个名为 `findStringIndex` 的非泛型函数,该函数的功能是在一个 `String` 数组中查找给定 `String` 值的索引。若查找到匹配的字符串,`findStringIndex(_:_:)` 函数返回该字符串在数组中的索引值,则返回 `nil`
```swift
func findStringIndex(array: [String], _ valueToFind: String) -> Int? {
@ -302,9 +304,9 @@ if let foundIndex = findStringIndex(strings, "llama") {
// 打印 “The index of llama is 2”
```
如果只能查找字符串在数组中的索引,用处不是很大。不过,你可以写出相同功能的泛型函数 `findIndex(_:_:)`用占位类型 `T` 替换 `String` 类型。
如果只能查找字符串在数组中的索引,用处不是很大。不过,你可以用占位类型 `T` 替换 `String` 类型来写出具有相同功能的泛型函数 `findIndex(_:_:)`
下面展示了 `findStringIndex(_:_:)` 函数的泛型版本 `findIndex(_:_:)`。请注意这个函数仍然返回 `Int?`是因为函数返回的是一个可选的索引数,而不是从数组中得到的一个可选值。需要提醒的是,这个函数无法通过编译,原因在例子后面说明:
下面展示了 `findStringIndex(_:_:)` 函数的泛型版本 `findIndex(_:_:)`。请注意这个函数返回值的类型仍然是 `Int?`是因为函数返回的是一个可选的索引数,而不是从数组中得到的一个可选值。需要提醒的是,这个函数无法通过编译,原因在例子后面说明:
```swift
func findIndex<T>(array: [T], _ valueToFind: T) -> Int? {
@ -317,9 +319,9 @@ func findIndex<T>(array: [T], _ valueToFind: T) -> Int? {
}
```
上面所写的函数无法通过编译。这个问题出在相等性检查上,即 `if value == valueToFind`。不是所有的 Swift 类型都可以用等式符(`==`)进行比较。例如,如果你创建一个你自己的类或结构体来表示一个复杂的数据模型,那么 Swift 无法猜到对于这个类或结构体而言“相等”意味着什么。正因如此,这部分代码无法保证适用于每个可能的类型 `T`,当你试图编译这部分代码时会出现相应的错误。
上面所写的函数无法通过编译。问题出在相等性检查上,即 "`if value == valueToFind`"。不是所有的 Swift 类型都可以用等式符(`==`)进行比较。比如说,如果你创建一个自定义的类或结构体来表示一个复杂的数据模型,那么 Swift 无法猜到对于这个类或结构体而言“相等”意味着什么。正因如此,这部分代码无法保证适用于每个可能的类型 `T`,当你试图编译这部分代码时会出现相应的错误。
不过所有的这些并不会让我们无从下手。Swift 标准库中定义了一个 `Equatable` 协议,该协议要求任何符合该协议的类型必须实现等式符(`==`,从而能对符合该协议的类型的任意两个值进行比较。所有的 Swift 标准类型自动支持 `Equatable` 协议。
不过所有的这些并不会让我们无从下手。Swift 标准库中定义了一个 `Equatable` 协议,该协议要求任何遵循该协议的类型必须实现等式符(`==`及不等符(`!=`),从而能对该类型的任意两个值进行比较。所有的 Swift 标准类型自动支持 `Equatable` 协议。
任何 `Equatable` 类型都可以安全地使用在 `findIndex(_:_:)` 函数中,因为其保证支持等式操作符。为了说明这个事实,当你定义一个函数时,你可以定义一个 `Equatable` 类型约束作为类型参数定义的一部分:
@ -334,7 +336,7 @@ func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {
}
```
`findIndex(_:_:)` 中的这个单一类型参数写做 `T: Equatable`,也就意味着“任何符合 `Equatable` 协议的 `T` 类型”。
`findIndex(_:_:)` 唯一的类型参数写做 `T: Equatable`,也就意味着“任何符合 `Equatable` 协议的类型 `T` ”。
`findIndex(_:_:)` 函数现在可以成功编译了,并且可以作用于任何符合 `Equatable` 的类型,如 `Double``String`
@ -348,7 +350,7 @@ let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
<a name="associated_types"></a>
## 关联类型
定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分将会非常有用。关联类型为协议的一部分,为某个类型提供了一个占位名(或者说别名),其代表的实际类型在协议被采纳时才会被指定。你可以通过 `typealias` 关键字来指定关联类型。
定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分将会非常有用。关联类型为协议的某个类型提供了一个占位名(或者说别名),其代表的实际类型在协议被采纳时才会被指定。你可以通过 `associatedtype` 关键字来指定关联类型。
<a name="associated_types_in_action"></a>
### 关联类型实践
@ -357,26 +359,26 @@ let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
```swift
protocol Container {
typealias ItemType
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
```
`Container` 协议定义了三个任何采纳协议的类型必须提供的功能:
`Container` 协议定义了三个任何采纳了该协议的类型(即容器)必须提供的功能:
- 必须可以通过 `append(_:)` 方法添加一个新元素到容器里。
- 必须可以通过 `count` 属性获取容器中元素的数量,并返回一个 `Int` 值。
- 必须可以通过接受 `Int` 索引值的下标检索到每一个元素。
- 必须可以通过索引值类型为 `Int` 的下标检索到容器中的每一个元素。
这个协议没有指定容器中元素该如何存储,以及元素必须是何种类型。这个协议只指定了三个任何采纳 `Container` 协议的类型必须提供的功能。采纳协议的类型在满足这三个条件的情况下也可以提供其他额外的功能。
这个协议没有指定容器中元素该如何存储,以及元素必须是何种类型。这个协议只指定了三个任何遵从 `Container` 协议的类型必须提供的功能。遵从协议的类型在满足这三个条件的情况下也可以提供其他额外的功能。
任何采纳 `Container` 协议的类型必须能够指定其存储的元素的类型,必须保证只有正确类型的元素可以加进容器中,必须明确通过其下标返回的元素的类型。
任何遵从 `Container` 协议的类型必须能够指定其存储的元素的类型,必须保证只有正确类型的元素可以加进容器中,必须明确通过其下标返回的元素的类型。
为了定义这三个条件,`Container` 协议需要在不知道容器中元素的具体类型的情况下引用这种类型。`Container` 协议需要指定任何通过 `append(_:)` 方法添加到容器中的元素和容器中的元素是相同类型,并且通过容器下标返回的元素的类型也是这种类型。
为了达到目的,`Container` 协议声明了一个关联类型 `ItemType`,写作 `typealias ItemType`。这个协议无法定义 `ItemType` 是什么类型的别名,这个信息将留给采纳协议的类型来提供。尽管如此,`ItemType` 别名提供了一种方式来引用 `Container` 中元素的类型,并将之用于 `append(_:)` 方法和下标,从而保证任何 `Container`预期行为都能够被执行。
为了达到这个目的,`Container` 协议声明了一个关联类型 `ItemType`,写作 `associatedtype ItemType`。这个协议无法定义 `ItemType` 是什么类型的别名,这个信息将留给遵从协议的类型来提供。尽管如此,`ItemType` 别名提供了一种方式来引用 `Container` 中元素的类型,并将之用于 `append(_:)` 方法和下标,从而保证任何 `Container` 的行为都能够正如预期地被执行。
下面是先前的非泛型的 `IntStack` 类型,这一版本采纳并符合了 `Container` 协议:
@ -406,11 +408,11 @@ struct IntStack: Container {
`IntStack` 结构体实现了 `Container` 协议的三个要求,其原有功能也不会和这些要求相冲突。
此外,`IntStack` 指定 `ItemType``Int` 类型,即 `typealias ItemType = Int`,从而将 `Container` 协议中抽象的 `ItemType` 类型转换为具体的 `Int` 类型。
此外,`IntStack` 在实现 `Container` 的要求时,指定 `ItemType``Int` 类型,即 `typealias ItemType = Int`,从而将 `Container` 协议中抽象的 `ItemType` 类型转换为具体的 `Int` 类型。
由于 Swift 的类型推断,你实际上不用在 `IntStack` 的定义中声明 `ItemType``Int`。因为 `IntStack` 符合 `Container` 协议的所有要求Swift 只需通过 `append(_:)` 方法的 `item` 参数类型和下标返回值的类型,就可以推断出 `ItemType` 的具体类型。事实上,如果你在上面的代码中删除了 `typealias ItemType = Int` 这一行,一切仍旧可以正常工作,因为 Swift 清楚地知道 `ItemType` 应该是种类型。
由于 Swift 的类型推断,你实际上不用在 `IntStack` 的定义中声明 `ItemType``Int`。因为 `IntStack` 符合 `Container` 协议的所有要求Swift 只需通过 `append(_:)` 方法的 `item` 参数类型和下标返回值的类型,就可以推断出 `ItemType` 的具体类型。事实上,如果你在上面的代码中删除了 `typealias ItemType = Int` 这一行,一切仍旧可以正常工作,因为 Swift 清楚地知道 `ItemType` 应该是种类型。
你也可以泛型 `Stack` 结构体符合 `Container` 协议:
你也可以泛型 `Stack` 结构体遵从 `Container` 协议:
```swift
struct Stack<Element>: Container {
@ -442,7 +444,7 @@ struct Stack<Element>: Container {
[通过扩展添加协议一致性](./22_Protocols.html#adding_protocol_conformance_with_an_extension)中描述了如何利用扩展让一个已存在的类型符合一个协议,这包括使用了关联类型的协议。
Swift 的 `Array` 已经提供 `append(_:)` 方法,一个 `count` 属性,以及一个接受 `Int` 型索引值的可用来检索数组元素的下标。这三个功能都符合 `Container` 协议的要求,也就意味着你可以扩展 `Array` 去符合 `Container` 协议,只需简单地声明 `Array` 采纳该协议即可。你可以通过一个空扩展来实现这点,正如[通过扩展采纳协议](./22_Protocols.html#declaring_protocol_adoption_with_an_extension)中的描述:
Swift 的 `Array` 类型已经提供 `append(_:)` 方法,一个 `count` 属性,以及一个接受 `Int` 型索引值的下标用以检索其元素。这三个功能都符合 `Container` 协议的要求,也就意味着你只需简单地声明 `Array` 采纳该协议就可以扩展 `Array`,使其遵从 `Container` 协议。你可以通过一个空扩展来实现这点,正如[通过扩展采纳协议](./22_Protocols.html#declaring_protocol_adoption_with_an_extension)中的描述:
```swift
extension Array: Container {}
@ -455,7 +457,7 @@ extension Array: Container {}
[类型约束](#type_constraints)让你能够为泛型函数或泛型类型的类型参数定义一些强制要求。
为关联类型定义约束也是非常有用的。你可以在参数列表中通过 `where` 子句为关联类型定义约束。一个 `where` 子句能够使一个关联类型符合某个特定的协议,以及某个特定的类型参数和关联类型必须类型相同。你可以通过将 `where` 关键字紧跟在类型参数列表后面来定义 `where` 子句,`where` 子句后跟一个或者多个针对关联类型的约束,以及一个或多个类型参数和关联类型间的相等关系。
为关联类型定义约束也是非常有用的。你可以在参数列表中通过 `where` 子句为关联类型定义约束。你能通过 `where` 子句要求一个关联类型遵从某个特定的协议,以及某个特定的类型参数和关联类型必须类型相同。你可以通过将 `where` 关键字紧跟在类型参数列表后面来定义 `where` 子句,`where` 子句后跟一个或者多个针对关联类型的约束,以及一个或多个类型参数和关联类型间的相等关系。
下面的例子定义了一个名为 `allItemsMatch` 的泛型函数,用来检查两个 `Container` 实例是否包含相同顺序的相同元素。如果所有的元素能够匹配,那么返回 `true`,否则返回 `false`
@ -486,7 +488,7 @@ func allItemsMatch<
这个函数接受 `someContainer``anotherContainer` 两个参数。参数 `someContainer` 的类型为 `C1`,参数 `anotherContainer` 的类型为 `C2``C1``C2` 是容器的两个占位类型参数,函数被调用时才能确定它们的具体类型。
这个函数的类型参数列表还定义了两个类型参数的要求:
这个函数的类型参数列表还定义了两个类型参数的要求:
- `C1` 必须符合 `Container` 协议(写作 `C1: Container`)。
- `C2` 必须符合 `Container` 协议(写作 `C2: Container`)。
@ -504,7 +506,7 @@ func allItemsMatch<
第三个和第四个要求结合起来意味着 `anotherContainer` 中的元素也可以通过 `!=` 操作符来比较,因为它们和 `someContainer` 中的元素类型相同。
这些要求让 `allItemsMatch(_:_:)` 函数能够比较两个容器,即使它们是不同的容器类型。
这些要求让 `allItemsMatch(_:_:)` 函数能够比较两个容器,即使它们的容器类型不同
`allItemsMatch(_:_:)` 函数首先检查两个容器是否拥有相同数量的元素,如果它们的元素数量不同,那么一定不匹配,函数就会返回 `false`
@ -530,4 +532,4 @@ if allItemsMatch(stackOfStrings, arrayOfStrings) {
// 打印 “All items match.”
```
上面的例子创建一个 `Stack` 实例来存储一些 `String` 值,然后将三个字符串压入栈中。这个例子还通过数组字面量创建了一个 `Array` 实例,数组中包含三个同栈中一样的字符串。即使栈和数组是不同的类型,但它们都符合 `Container` 协议,而且它们都包含相同类型的值。因此你可以用这两个容器作为参数来调用 `allItemsMatch(_:_:)` 函数。在上面的例子中,`allItemsMatch(_:_:)` 函数正确地显示了这两个容器中的所有元素都是相互匹配的。
上面的例子创建一个 `Stack` 实例来存储一些 `String` 值,然后将三个字符串压入栈中。这个例子还通过数组字面量创建了一个 `Array` 实例,数组中包含同栈中一样的三个字符串。即使栈和数组是不同的类型,但它们都遵从 `Container` 协议,而且它们都包含相同类型的值。因此你可以用这两个容器作为参数来调用 `allItemsMatch(_:_:)` 函数。在上面的例子中,`allItemsMatch(_:_:)` 函数正确地显示了这两个容器中的所有元素都是相互匹配的。

View File

@ -5,32 +5,41 @@
> 翻译:[superkam](https://github.com/superkam)
> 校对:[numbbbbb](https://github.com/numbbbbb)
> 2.0
> 翻译+校对:[buginux](https://github.com/buginux)
> 2.1
> 翻译:[mmoaay](https://github.com/mmoaay)
> 2.2
> 翻译+校对:[星夜暮晨](https://github.com/semperidem)2016-04-06
本页包含内容:
- [空白与注释](#whitespace_and_comments)
- [标识符](#identifiers)
- [关键字和标点符号](#keywords)
- [字面量](#literals)
- [整数字面量](#integer_literals)
- [浮点数字面量](#floating_point_literals)
- [字符串字面量](#string_literals)
- [整数字面量](#integer_literals)
- [浮点数字面量](#floating_point_literals)
- [字符串字面量](#string_literals)
- [运算符](#operators)
Swift 的“词法结构描述了能构成该语言中合法符号的字符序列。这些合法符号组成了语言中最底层的构建基块,并在之后的章节中用于描述语言的其他部分。一个合法符号由一个标识符、关键字、标点符号、字面量或运算符组成。
Swift 的*“词法结构 (lexical structure)”* 描述了能构成该语言中合法符号 (token) 的字符序列。这些合法符号组成了语言中最底层的构建基块,并在之后的章节中用于描述语言的其他部分。一个合法符号由一个标识符 (identifier)、关键字 (keyword)、标点符号 (punctuation)、字面量 (literal) 或运算符 (operator) 组成。
通常情况下,符号是根据随后将介绍的语法约束,由 Swift 源文件的输入文本中提取可能的最长子串生成。这种方法称为“最长匹配,或者“最大适合
通常情况下,通过考虑输入文本当中可能的最长子串,并且在随后将介绍的语法约束之下,根据随后将介绍的语法约束生成的,根据 Swift 源文件当中的字符来生成相应的“符号”。这种方法称为*“最长匹配 (longest match)”*,或者*“最大适合(maximal munch)”*
<a id="whitespace_and_comments"></a>
## 空白与注释
空白有两个用途:分隔源文件中的符号以及帮助区分运算符属于前缀还是后缀(参见 [运算符](#operators)在其他情况下则会被忽略。以下的字符会被当作空白空格U+0020、换行符U+000A、回车符U+000D、水平制表符U+0009、垂直制表符U+000B、换页符U+000C以及空U+0000
空白 (whitespace) 有两个用途:分隔源文件中的符号以及帮助区分运算符属于前缀还是后缀(参见 [运算符](#operators)),在其他情况下空白则会被忽略。以下的字符会被当作空白空格U+0020、换行符U+000A、回车符U+000D、水平制表符U+0009、垂直制表符U+000B、换页符U+000C以及空字符U+0000
注释被编译器当作空白处理。单行注释由 `//` 开始直至遇到换行符U+000A或者回车符U+000D。多行注释由 `/*` 开始,以 `*/` 结束。注释允许嵌套,但注释标记必须匹配。
@ -39,9 +48,9 @@ Swift 的“词法结构”描述了能构成该语言中合法符号的字符
<a id="identifiers"></a>
## 标识符
标识符可以由以下的字符开始:大写或小写的字母 `A``Z`、下划线 `_`、基本多文种平面中的 Unicode 非组合字符以及基本多文种平面以外的非个人专用区字符。首字符之后,允许使用数字和 Unicode 字符组合
*标识符(identifier)* 可以由以下的字符开始:大写或小写的字母 `A``Z`、下划线 (`_`)、基本多文种平面 (Basic Multilingual Plane) 中非字符数字组合的 Unicode 字符以及基本多文种平面以外的非个人专用区字符。首字符之后,允许使用数字和组合 Unicode 字符。
使用保留字作为标识符,需要在其前后增加反引号 `` ` ``。例如,`class` 不是合法的标识符,但可以使用 `` `class` ``。反引号不属于标识符的一部分,`` `x` `` 和 `x` 表示同一标识符。
使用保留字作为标识符,需要在其前后增加反引号 (`` ` ``)。例如,`class` 不是合法的标识符,但可以使用 `` `class` ``。反引号不属于标识符的一部分,`` `x` `` 和 `x` 表示同一标识符。
闭包中如果没有明确指定参数名称,参数将被隐式命名为 `$0`、`$1`、`$2` 等等。这些命名在闭包作用域范围内是合法的标识符。
@ -51,6 +60,7 @@ Swift 的“词法结构”描述了能构成该语言中合法符号的字符
> *标识符* → [*头部标识符*](#identifier-head) [*标识符字符组*](#identifier-characters)<sub>可选</sub>
> *标识符* → \`[*头部标识符*](#identifier-head) [*标识符字符组*](#identifier-characters)<sub>可选</sub>\`
> *标识符* → [*隐式参数名*](#implicit-parameter-name)
<a id="identifier-list"></a>
> *标识符列表* → [*标识符*](#identifier) | [*标识符*](#identifier) **,** [*标识符列表*](#identifier-list)
@ -76,7 +86,7 @@ Swift 的“词法结构”描述了能构成该语言中合法符号的字符
> *标识符字符* → 数值 0 - 9
> *标识符字符* → U+0300U+036FU+1DC0U+1DFFU+20D0U+20FF或者 U+FE20U+FE2F
> *标识符字符* → [*头部标识符*](#identifier-head)
<a id="identifier-characters"></a>
> <a id="identifier-characters"></a>
> *标识符字符组* → [*标识符字符*](#identifier-character) [*标识符字符组*](#identifier-characters)<sub>可选</sub>
<a id="implicit-parameter-name"></a>
@ -85,20 +95,21 @@ Swift 的“词法结构”描述了能构成该语言中合法符号的字符
<a id="keywords"></a>
## 关键字和标点符号
下面这些被保留的关键字不允许用作标识符,除非反引号转义,具体描述请参考 [标识符](#identifiers)。
下面这些被保留的关键字不允许用作标识符,除非使用反引号转义,具体描述请参考 [标识符](#identifiers)。除了 `inout``var` 以及 `let` 之外的关键字可以用作某个函数声明或者函数调用当中的外部参数名,不用添加反引号转义。
* 用在声明中的关键字: `associatedtype``class``deinit``enum``extension``func``import``init``inout``internal``let``operator``private``protocol``public``static``struct``subscript``typealias` 以及 `var`
* 用在语句中的关键字:`break``case``continue``default``defer``do``else``fallthrough``for``guard``if``in``repeat``return``switch``where` 以及 `while`
* 用在表达式和类型中的关键字:`as``catch``dynamicType``false``is``nil``rethrows``super``self``Self``throw``throws``true``try``#column``#file``#function` 以及 `#line`
* 用在模式中的关键字:`_`
* 以井字号 (`#`) 开头的关键字:`#available``#column``#else#elseif``#endif``#file``#function``#if``#line` 以及 `#selector`
* 特定上下文中被保留的关键字: `associativity``convenience``dynamic``didSet``final``get``infix``indirect``lazy``left``mutating``none``nonmutating``optional``override``postfix``precedence``prefix``Protocol``required``right``set``Type``unowned``weak` 以及 `willSet`。这些关键字在特定上下文之外可以被用做标识符。
* 用在声明中的关键字: `class``deinit``enum``extension``func``import``init``inout``internal``let``operator``private``protocol``public``static``struct``subscript``typealias``var`
* 用在语句中的关键字: `break``case``continue``default``defer``do``else``fallthrough``for``guard``if``in``repeat``return``switch``where``while`
* 用在表达式和类型中的关键字: `as``catch``dynamicType``false``is``nil``rethrows``super``self``Self``throw``throws``true``try``__COLUMN__``__FILE__``__FUNCTION__``__LINE__`
* 用在模式中的关键字:`_`
* 特定上下文中被保留的关键字: `associativity``convenience``dynamic``didSet``final``get``infix``indirect``lazy``left``mutating``none``nonmutating``optional``override``postfix``precedence``prefix``Protocol``required``right``set``Type``unowned``weak``willSet`,这些关键字在特定上下文之外可以被用做标识符。
以下符号被当作保留符号,不能用于自定义运算符: `(``)``{``}``[``]``.``,``:``;``=``@``#``&`(作为前缀运算符)、`->`、`` ` ``、`?`、`!`(作为后缀运算符)。
<a id="literals"></a>
## 字面量
字面量用来表示源码中某种特定类型的值,比如一个数字或字符串。
*字面量 (literal)* 用来表示源码中某种特定类型的值,比如一个数字或字符串。
下面是字面量的一些示例:
@ -106,7 +117,7 @@ Swift 的“词法结构”描述了能构成该语言中合法符号的字符
42 // 整数字面量
3.14159 // 浮点数字面量
"Hello, world!" // 字符串字面量
true // 布尔值字面量
true // 布尔值字面量
```
字面量本身并不包含类型信息。事实上,一个字面量会被解析为拥有无限的精度,然后 Swift 的类型推导会尝试去推导出这个字面量的类型。比如,在 `let x: Int8 = 42` 这个声明中Swift 使用了显式类型标注(`: Int8`)来推导出 `42` 这个整数字面量的类型是 `Int8`。如果没有可用的类型信息, Swift 则会从标准库中定义的字面量类型中推导出一个默认的类型。整数字面量的默认类型是 `Int`,浮点数字面量的默认类型是 `Double`,字符串字面量的默认类型是 `String`,布尔值字面量的默认类型是 `Bool`。比如,在 `let str = "Hello, world"` 这个声明中,字符串 `"Hello, world"` 的默认推导类型就是 `String`。
@ -114,26 +125,25 @@ true // 布尔值字面量
当为一个字面量值指定了类型标注的时候,这个标注的类型必须能通过这个字面量值实例化。也就是说,这个类型必须符合这些 Swift 标准库协议中的一个:整数字面量的 `IntegerLiteralConvertible` 协议、浮点数字面量的 `FloatingPointLiteralConvertible` 协议、字符串字面量的 `StringLiteralConvertible` 协议以及布尔值字面量的 `BooleanLiteralConvertible` 协议。比如,`Int8` 符合 `IntegerLiteralConvertible` 协议,因此它能在 `let x: Int8 = 42` 这个声明中作为整数字面量 `42` 的类型标注。
> 字面量语法
> *字面量* → [*数值字面量*](#numeric-literal) | [*字符串字面量*](#string-literal) | [*布尔值字面量*](#boolean-literal) | [*nil 字面量*](#nil-literal)
<a id="numeric-literal"></a>
> *数值字面量* → **-**<sub>可选</sub> [*整数字面量*](#integer-literal) | **-**<sub>可选</sub> [*浮点数字面量*](#floating-point-literal)
<a id="boolean-literal"></a>
> <a id="boolean-literal"></a>
> *布尔值字面量* → **true** | **false**
<a id="nil-literal"></a>
> <a id="nil-literal"></a>
> *nil 字面量* → **nil**
<a id="integer_literals"></a>
### 整数字面量
整数字面量表示未指定精度整数的值。整数字面量默认用十进制表示,可以加前缀来指定其他的进制二进制字面量加 `0b`,八进制字面量加 `0o`,十六进制字面量加 `0x`。
*整数字面量 (Integer Literals)* 表示未指定精度整数的值。整数字面量默认用十进制表示,可以加前缀来指定其他的进制二进制字面量加 `0b`,八进制字面量加 `0o`,十六进制字面量加 `0x`。
十进制字面量包含数字 `0` 至 `9`。二进制字面量只包含 `0` 或 `1`,八进制字面量包含数字 `0` 至 `7`,十六进制字面量包含数字 `0` 至 `9` 以及字母 `A` 至 `F`(大小写均可)。
负整数的字面量在整数字面量前加负号 `-`,比如 `-42`。
整型字面面可以使用下划线 `_` 来增加数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,并不会影响字面量的值。
整型字面面可以使用下划线 (`_`) 来增加数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`这同样也会被系统所忽略,并不会影响字面量的值。
除非特别指定,整数字面量的默认推导类型为 Swift 标准库类型中的 `Int`。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 [整数](../chapter2/01_The_Basics.html#integers)。
@ -149,54 +159,54 @@ true // 布尔值字面量
> *二进制字面量* → **0b** [*二进制数字*](#binary-digit) [*二进制字面量字符组*](#binary-literal-characters)<sub>可选</sub>
> <a id="binary-digit"></a>
> *二进制数字* → 数值 0 到 1
<a id="binary-literal-character"></a>
> <a id="binary-literal-character"></a>
> *二进制字面量字符* → [*二进制数字*](#binary-digit) | _
<a id="binary-literal-characters"></a>
> <a id="binary-literal-characters"></a>
> *二进制字面量字符组* → [*二进制字面量字符*](#binary-literal-character) [*二进制字面量字符组*](#binary-literal-characters)<sub>可选</sub>
<a id="octal-literal"></a>
> *八进制字面量* → **0o** [*八进字数字*](#octal-digit) [*八进制字符组*](#octal-literal-characters)<sub>可选</sub>
<a id="octal-digit"></a>
> <a id="octal-digit"></a>
> *八进字数字* → 数值 0 到 7
<a id="octal-literal-character"></a>
> <a id="octal-literal-character"></a>
> *八进制字符* → [*八进字数字*](#octal-digit) | _
<a id="octal-literal-characters"></a>
> <a id="octal-literal-characters"></a>
> *八进制字符组* → [*八进制字符*](#octal-literal-character) [*八进制字符组*](#octal-literal-characters)<sub>可选</sub>
<a id="decimal-literal"></a>
> *十进制字面量* → [*十进制数字*](#decimal-digit) [*十进制字符组*](#decimal-literal-characters)<sub>可选</sub>
<a id="decimal-digit"></a>
> <a id="decimal-digit"></a>
> *十进制数字* → 数值 0 到 9
<a id="decimal-digits"></a>
> <a id="decimal-digits"></a>
> *十进制数字组* → [*十进制数字*](#decimal-digit) [*十进制数字组*](#decimal-digits)<sub>可选</sub>
<a id="decimal-literal-character"></a>
> <a id="decimal-literal-character"></a>
> *十进制字符* → [*十进制数字*](#decimal-digit) | _
<a id="decimal-literal-characters"></a>
> <a id="decimal-literal-characters"></a>
> *十进制字符组* → [*十进制字符*](#decimal-literal-character) [*十进制字符组*](#decimal-literal-characters)<sub>可选</sub>
<a id="hexadecimal-literal"></a>
> *十六进制字面量* → **0x** [*十六进制数字*](#hexadecimal-digit) [*十六进制字面量字符组*](#hexadecimal-literal-characters)<sub>可选</sub>
<a id="hexadecimal-digit"></a>
> <a id="hexadecimal-digit"></a>
> *十六进制数字* → 数值 0 到 9, 字母 a 到 f, 或 A 到 F
<a id="hexadecimal-literal-character"></a>
> <a id="hexadecimal-literal-character"></a>
> *十六进制字符* → [*十六进制数字*](#hexadecimal-digit) | _
<a id="hexadecimal-literal-characters"></a>
> <a id="hexadecimal-literal-characters"></a>
> *十六进制字面量字符组* → [*十六进制字符*](#hexadecimal-literal-character) [*十六进制字面量字符组*](#hexadecimal-literal-characters)<sub>可选</sub>
<a id="floating_point_literals"></a>
### 浮点数字面量
浮点数字面量表示未指定精度浮点数的值。
*浮点数字面量 (Floating-point literals)* 表示未指定精度浮点数的值。
浮点数字面量默认用十进制表示(无前缀),也可以用十六进制表示(加前缀 `0x`)。
十进制浮点数字面量由十进制数字串后跟小数部分或指数部分(或两者皆有)组成。十进制小数部分由小数点 `.` 后跟十进制数字串组成。指数部分由大写或小写字母 `e` 为前缀后跟十进制数字串组成,这串数字表示 `e` 之前的数量乘以 10 的几次方。例如:`1.25e2` 表示 `1.25 10^2`,也就是 `125.0`;同样,`1.25e2` 表示 `1.25 10^2`,也就是 `0.0125`。
十进制浮点数字面量由十进制数字串后跟小数部分或指数部分(或两者皆有)组成。十进制小数部分由小数点 (`.`) 后跟十进制数字串组成。指数部分由大写或小写字母 `e` 为前缀后跟十进制数字串组成,这串数字表示 `e` 之前的数量乘以 10 的几次方。例如:`1.25e2` 表示 1.25 x 10²,也就是 `125.0`;同样,`1.25e2` 表示 1.25 x 10¯²,也就是 `0.0125`。
十六进制浮点数字面量由前缀 `0x` 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字串组成。指数部分由大写或小写字母 `p` 为前缀后跟十进制数字串组成,这串数字表示 `p` 之前的数量乘以 2 的几次方。例如:`0xFp2` 表示 `15 2^2`,也就是 `60`;同样,`0xFp-2` 表示 `15 2^-2`,也就是 `3.75`。
十六进制浮点数字面量由前缀 `0x` 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字串组成。指数部分由大写或小写字母 `p` 为前缀后跟十进制数字串组成,这串数字表示 `p` 之前的数量乘以 2 的几次方。例如:`0xFp2` 表示 15 x 2²,也就是 `60`;同样,`0xFp-2` 表示 15 x 2¯²,也就是 `3.75`。
负数的浮点数字面量由负号 `-` 和浮点数字面量组成,例如 `-42.5`。
负数的浮点数字面量由负号 (`-`) 和浮点数字面量组成,例如 `-42.5`。
浮点数字面量允许使用下划线 `_` 来增强数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,并不会影响字面量的值。
浮点数字面量允许使用下划线 (`_`) 来增强数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 `0`,并不会影响字面量的值。
除非特别指定,浮点数字面量的默认推导类型为 Swift 标准库类型中的 `Double`,表示 64 位浮点数。Swift 标准库也定义了 `Float` 类型,表示 32 位浮点数。
@ -208,19 +218,19 @@ true // 布尔值字面量
<a id="decimal-fraction"></a>
> *十进制分数* → **.** [*十进制字面量*](#decimal-literal)
<a id="decimal-exponent"></a>
> <a id="decimal-exponent"></a>
> *十进制指数* → [*十进制指数 e*](#floating-point-e) [*正负号*](#sign)<sub>可选</sub> [*十进制字面量*](#decimal-literal)
<a id="hexadecimal-fraction"></a>
> *十六进制分数* → **.** [*十六进制数字*](#hexadecimal-digit) [*十六进制字面量字符组*](#hexadecimal-literal-characters)<sub>可选</sub>
<a id="hexadecimal-exponent"></a>
> <a id="hexadecimal-exponent"></a>
> *十六进制指数* → [*十六进制指数 p*](#floating-point-p) [*正负号*](#sign)<sub>可选</sub> [*十进制字面量*](#decimal-literal)
<a id="floating-point-e"></a>
> *十进制指数 e* → **e** | **E**
<a id="floating-point-p"></a>
> <a id="floating-point-p"></a>
> *十六进制指数 p* → **p** | **P**
<a id="sign"></a>
> <a id="sign"></a>
> *正负号* → **+** | **-**
<a id="string_literals"></a>
@ -243,7 +253,7 @@ true // 布尔值字面量
* 单引号 `\'`
* Unicode 标量 `\u{`n`}`n 为一到八位的十六进制数字
字符串字面量允许在反斜杠 `\` 后的括号 `()` 中插入表达式的值。插入表达式可以包含字符串字面量,但不能包含未转义的双引号 `"`、未转义的反斜线 `\`、回车符换行符。
字符串字面量允许在反斜杠 (`\`) 后的括号 `()` 中插入表达式的值。插入表达式可以包含字符串字面量,但不能包含未转义的双引号 (`"`)、未转义的反斜线 (`\`)、回车符以及换行符。
例如,以下所有字符串字面量的值都是相同的:
@ -271,23 +281,23 @@ let textB = "Hello world"
<a id="static-string-literal"></a>
> *静态字符串字面量* → **"**[*引用文本*](#quoted-text)<sub>可选</sub>**"**
<a id="quoted-text"></a>
> <a id="quoted-text"></a>
> *引用文本* → [*引用文本项*](#quoted-text-item) [*引用文本*](#quoted-text)<sub>可选</sub>
<a id="quoted-text-item"></a>
> <a id="quoted-text-item"></a>
> *引用文本项* → [*转义字符*](#escaped-character)
> *引用文本项* → 除了 **"**、**\\**、U+000A、U+000D 以外的所有 Unicode 字符
<a id="interpolated-string-literal"></a>
> *插值字符串字面量* → **"**[*插值文本*](#interpolated-text)<sub>可选</sub>**"**
<a id="interpolated-text"></a>
> <a id="interpolated-text"></a>
> *插值文本* → [*插值文本项*](#interpolated-text-item) [*插值文本*](#interpolated-text)<sub>可选</sub>
<a id="interpolated-text-item"></a>
> <a id="interpolated-text-item"></a>
> *插值文本项* → **\\****(**[*表达式*](./04_Expressions.html)**)** | [*引用文本项*](#quoted-text-item)
<a id="escaped-character"></a>
> *转义字符* → **\\****0** | **\\****\\** | **\t** | **\n** | **\r** | **\\"** | **\\'**
> *转义字符* → **\u {** [*unicode 标量数字*](#unicode-scalar-digits) **}**
<a id="unicode-scalar-digits"></a>
> <a id="unicode-scalar-digits"></a>
> *unicode 标量数字* → 一到八位的十六进制数字
<a id="operators"></a>
@ -295,17 +305,21 @@ let textB = "Hello world"
Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基础运算符](../chapter2/02_Basic_Operators.html) 和 [高级运算符](../chapter2/25_Advanced_Operators.html) 中进行了阐述。这一小节将描述哪些字符能用于自定义运算符。
自定义运算符可以由以下其中之一的 ASCII 字符 `/``=``-``+``!``*``%``<``>``&``|``^``?` 以及 `~`,或者后面语法中规定的任一个 Unicode 字符开始。在第一个字符之后,允许使用组合型 Unicode 字符。也可以使用两个或者多个的点号来自定义运算符(比如,`....`)。虽然可以自定义包含问号 `?` 的运算符,但是这个运算符不能只包含单独的一个问号
自定义运算符可以由以下其中之一的 ASCII 字符 `/``=``-``+``!``*``%``<``>``&``|``^``?` 以及 `~`,或者后面语法中规定的任一个 Unicode 字符(其中包含了*数学运算符*、*零散符号(Miscellaneous Symbols)* 以及印刷符号 (Dingbats) 之类的 Unicode 块)开始。在第一个字符之后,允许使用组合型 Unicode 字符。
您也可以以点号 (`.`) 开头来定义自定义运算符。这些运算符可以包含额外的点,例如 `.+.`。如果某个运算符不是以点号开头的,那么它就无法再包含另外的点号了。例如,`+.+` 就会被看作为一个 `+` 运算符后面跟着一个 `.+` 运算符。
虽然您可以用问号 `?` 来自定义运算符,但是这个运算符不能只包含单独的一个问号。此外,虽然运算符可以包含一个惊叹号 `!`,但是前缀运算符不能够以问号或者惊叹号开头。
> 注意
以下这些标记 `=``->``//``/*``*/``.``<`(前缀运算符)、`&``?``?`(中缀运算符)、`>`(后缀运算符)、`!``?` 是被系统保留的。这些符号不能被重载,也不能用于自定义运算符。
> 以下这些标记 `=``->``//``/*``*/`、`.`、`<`(前缀运算符)、`&`、`?`、`?`(中缀运算符)、`>`(后缀运算符)、`!` 、`?` 是被系统保留的。这些符号不能被重载,也不能用于自定义运算符。
运算符两侧的空白被用来区分该运算符是否为前缀运算符、后缀运算符或二元运算符。规则总结如下:
* 如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:`a+b``a + b` 中的运算符 `+` 被看作二元运算符。
* 如果运算符只有左侧空白,将被看作前缀一元运算符。例如 `a ++b` 中的 `++` 被看作前缀一元运算符。
* 如果运算符只有右侧空白,将被看作后缀一元运算符。例如 `a++ b` 中的 `++` 被看作后缀一元运算符。
* 如果运算符左侧没有空白并紧跟 `.`,将被看作后缀一元运算符。例如 `a++.b` 中的 `++` 被看作后缀一元运算符(即上式被视为 `a++ .b` `a ++ .b`)。
* 如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:`a+++b``a +++ b` 中的 `+++` 运算符会被看作二元运算符。
* 如果运算符只有左侧空白,将被看作一元前缀运算符。例如 `a +++b` 中的 `+++` 运算符会被看做是一元前缀运算符。
* 如果运算符只有右侧空白,将被看作一元后缀运算符。例如 `a+++ b` 中的 `+++` 运算符会被看作是一元后缀运算符。
* 如果运算符左侧没有空白并紧跟 `.`,将被看作一元后缀运算符。例如 `a+++.b` 中的 `+++` 运算符会被视为一元后缀运算符(即上式被视为 `a+++ .b`不是 `a +++ .b`)。
鉴于这些规则,运算符前的字符 `(``[``{`,运算符后的字符 `)``]``}`,以及字符 `,``;``:` 都被视为空白。
@ -346,19 +360,19 @@ Swift 标准库定义了许多可供使用的运算符,其中大部分在 [基
> *运算符字符* → U+FE00U+FE0F
> *运算符字符* → U+FE20U+FE2F
> *运算符字符* → U+E0100U+E01EF
<a id="operator-characters"></a>
> <a id="operator-characters"></a>
> *运算符字符组* → [*运算符字符*](#operator-character) [*运算符字符组*](#operator-characters)<sub>可选</sub>
<a id="dot-operator-head"></a>
> *头部点运算符* → **..**
<a id="dot-operator-character"></a>
> <a id="dot-operator-character"></a>
> *点运算符字符* → **.** | [*运算符字符*](#operator-character)
<a id="dot-operator-characters"></a>
> <a id="dot-operator-characters"></a>
> *点运算符字符组* → [*点运算符字符*](#dot-operator-character) [*点运算符字符组*](#dot-operator-characters)<sub>可选</sub>
<a id="binary-operator"></a>
> *二元运算符* → [*运算符*](#operator)
<a id="prefix-operator"></a>
> <a id="prefix-operator"></a>
> *前缀运算符* → [*运算符*](#operator)
<a id="postfix-operator"></a>
> <a id="postfix-operator"></a>
> *后缀运算符* → [*运算符*](#operator)

View File

@ -11,6 +11,9 @@
> 2.1
> 翻译:[mmoaay](https://github.com/mmoaay)
> 2.2
> 校对:[175](https://github.com/Brian175)
本页包含内容:
- [前缀表达式](#prefix_expressions)
@ -27,6 +30,7 @@
- [隐式成员表达式](#implicit_member_expression)
- [圆括号表达式](#parenthesized_expression)
- [通配符表达式](#wildcard_expression)
- [选择器表达式](#selector_expression)
- [后缀表达式](#postfix_expressions)
- [函数调用表达式](#function_call_expression)
- [构造器表达式](#initializer_expression)
@ -37,9 +41,9 @@
- [强制取值表达式](#forced-Value_expression)
- [可选链表达式](#optional-chaining_expression)
Swift 中存在四种表达式:前缀表达式,二元表达式,基本表达式和后缀表达式。表达式可以返回一个值,还可以执行某些代码
Swift 中存在四种表达式:前缀表达式,二元表达式,基本表达式和后缀表达式。表达式返回一个值的同时还可以引发副作用
前缀表达式和二元表达式就是对某些表达式使用各种运算符。基本表达式是最短小的表达式,它提供了获取值的一种途径。后缀表达式则允许你建立复杂的表达式,例如函数调用和成员访问。每种表达式都在下面有详细论述。
通过前缀表达式和二元表达式可以对简单表达式使用各种运算符。基本表达式从概念上讲是最简单的一种表达式,它是一种访问值的方式。后缀表达式则允许你建立复杂的表达式,例如函数调用和成员访问。每种表达式都在下面有详细论述。
> 表达式语法
<a name="expression"></a>
@ -50,20 +54,20 @@ Swift 中存在四种表达式:前缀表达式,二元表达式,基本表
<a name="prefix_expressions"></a>
## 前缀表达式
前缀表达式由可选的前缀运算符和表达式组成。前缀运算符只接收一个参数。
前缀表达式由可选的前缀运算符和表达式组成。前缀运算符只接收一个参数,表达式则紧随其后
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.html) 和 [高级运算符](../chapter2/25_Advanced_Operators.html)。
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/25_Advanced_Operators.md)。
关于 Swift 标准库提供的运算符的更多信息,请参阅 [*Swift Standard Library Operators Reference*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.html#//apple_ref/doc/uid/TP40016054)。
除了标准库运算符,你也可以对某个变量使用 `&` 运算符,从而将其传递给函数的输入输出参数。 更多信息,请参阅 [输入输出参数](../chapter2/06_Functions.html#in_out_parameters)。
除了标准库运算符,你也可以对某个变量使用 `&` 运算符,从而将其传递给函数的输入输出参数。更多信息,请参阅 [输入输出参数](../chapter2/06_Functions.html#in_out_parameters)。
> 前缀表达式语法
<a name="prefix-expression"></a>
> *前缀表达式* → [*前缀运算符*](02_Lexical_Structure.html#prefix-operator)<sub>可选</sub> [*后缀表达式*](#postfix-expression)
> *前缀表达式* → [*前缀运算符*](02_Lexical_Structure.md#prefix-operator)<sub>可选</sub> [*后缀表达式*](#postfix-expression)
> *前缀表达式* → [*输入输出表达式*](#in-out-expression)
<a name="in-out-expression"></a>
> *输入输出表达式* → **&** [*标识符*](02_Lexical_Structure.html#identifier)
> *输入输出表达式* → **&** [*标识符*](02_Lexical_Structure.md#identifier)
<a name="try_operator"></a>
### try 运算符
@ -87,15 +91,14 @@ try 表达式由 `try` 运算符加上紧随其后的可抛出错误的表达式
在二进制运算符左侧的表达式被标记上 `try``try?` 或者 `try!` 时,这个运算符对整个二进制表达式都产生作用。也就是说,你可以使用括号来明确运算符的作用范围。
```swift
sum = try someThrowingFunction() + anotherThrowingFunction() // try 对两个方法调用都产生作用
sum = try (someThrowingFunction() + anotherThrowingFunction()) // try 对两个方法调用都产生作用
sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try 只对第一个方法调用产生作用
sum = try someThrowingFunction() + anotherThrowingFunction() // try 对两个函数调用都产生作用
sum = try (someThrowingFunction() + anotherThrowingFunction()) // try 对两个函数调用都产生作用
sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try 只对第一个函数调用产生作用
```
`try` 表达式不能出现在二进制运算符的的右侧,除非二进制运算符是赋值运算符或者 `try` 表达式是被圆括号括起来的。
关于 `try``try?``try!` 的更多信息,以及如何使用的例子,请参阅 [错误处理](../chapter2/18_Error_Handling.html)。
关于 `try``try?``try!` 的更多信息,以及如何使用的例子,请参阅 [错误处理](../chapter2/18_Error_Handling.html)。
> try 表达式语法
<a name="try-operator"></a>
> *try 运算符* → **try** | **try?** | **try!**
@ -103,20 +106,20 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try
<a name="binary_expressions"></a>
## 二元表达式
二元表达式形式如下:
二元表达式由中缀运算符和左右参数表达式组成。形式如下:
> `左侧参数` `二元运算符` `右侧参数`
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.html) 和 [高级运算符](../chapter2/25_Advanced_Operators.html)。
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/25_Advanced_Operators.md)。
关于 Swift 标准库提供的运算符的更多信息,请参阅 [*Swift Standard Library Operators Reference*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.html#//apple_ref/doc/uid/TP40016054)。
> 注意
> 在解析时,一个二元表达式将作为一个简单列表表示,然后根据运算符的优先级,再进一步进行组合。例如,`2 + 3 * 5` 首先被看作具有五个元素的列表,即 `2`、`+`、`3`、`*`、`5`,随后根据运算符优先级组合为 `(2 + (3 * 5))`。
> 在解析时,一个二元表达式将作为一个扁平列表表示,然后根据运算符的优先级,再进一步进行组合。例如,`2 + 3 * 5` 首先被看作具有五个元素的列表,即 `2`、`+`、`3`、`*`、`5`,随后根据运算符优先级组合为 `(2 + (3 * 5))`。
<a name="binary-expression"></a>
> 二元表达式语法
> *二元表达式* → [*二元运算符*](02_Lexical_Structure.html#binary-operator) [*前缀表达式*](#prefix-expression)
> *二元表达式* → [*二元运算符*](02_Lexical_Structure.md#binary-operator) [*前缀表达式*](#prefix-expression)
> *二元表达式* → [*赋值运算符*](#assignment-operator) [*try运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression)
> *二元表达式* → [*条件运算符*](#conditional-operator) [*try运算符*](#try-operator)<sub>可选</sub> [*前缀表达式*](#prefix-expression)
> *二元表达式* → [*类型转换运算符*](#type-casting-operator)
@ -130,7 +133,7 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try
> `表达式` = `值`
右边的值会被赋值给左边的表达式。如果左边表达式是一个元组,那么右边必须是一个具有同样元素个数的元组。嵌套元组也是允许的。
右边的值会被赋值给左边的表达式。如果左边表达式是一个元组,那么右边必须是一个具有同样元素个数的元组。嵌套元组也是允许的。)右边的值中的每一部分都会被赋值给左边的表达式中的相应部分。例如:
```swift
(a, _, (b, c)) = ("test", 9.45, (12, 3))
@ -152,7 +155,7 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try
如果条件为真,那么对第一个表达式进行求值并返回结果。否则,对第二个表达式进行求值并返回结果。未使用的表达式不会进行求值。
关于使用三元条件运算符的例子,请参阅 [三元条件运算符](../chapter2/02_Basic_Operators.html#ternary_conditional_operator)。
关于使用三元条件运算符的例子,请参阅 [三元条件运算符](../chapter2/02_Basic_Operators.md#ternary_conditional_operator)。
> 三元条件运算符语法
<a name="conditional-operator"></a>
@ -161,11 +164,11 @@ sum = (try someThrowingFunction()) + anotherThrowingFunction() // 错误try
<a name="type-casting_operators"></a>
### 类型转换运算符
有 4 种类型转换运算符:`is``as``? ``!`。它们有如下的形式:
有 4 种类型转换运算符:`is``as``as? ``as!`。它们有如下的形式:
> `表达式` is `类型`
`表达式` as `类型`
`表达式` is? `类型`
`表达式` as? `类型`
`表达式` as! `类型`
`is` 运算符在运行时检查表达式能否向下转化为指定的类型,如果可以则返回 `ture`,否则返回 `false`
@ -187,25 +190,25 @@ f(x as Any)
// 打印 “Function for Any”
```
桥接可将 Swift 标准库中的类型(例如 `String`)作为一个与之相关的 Foundation 类型(例如 `NSString`)来使用,而不需要新建一个实例。关于桥接的更多信息,请参阅 [*Using Swift with Cocoa and Objective-C*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中的 [Working with Cocoa Data Types](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)。
桥接可将 Swift 标准库中的类型(例如 `String`)作为一个与之相关的 Foundation 类型(例如 `NSString`)来使用,而不需要新建一个实例。关于桥接的更多信息,请参阅 [*Using Swift with Cocoa and Objective-C (Swift2.2)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中的 [Working with Cocoa Data Types](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6)。
`as?` 运算符有条件地执行类型转换,返回目标类型的可选值。在运行时,如果转换成功,返回的可选值将包含转换后的值,否则返回 `nil`。如果在编译时就能确定转换一定会成功或是失败,则会编译错。
`as?` 运算符有条件地执行类型转换,返回目标类型的可选值。在运行时,如果转换成功,返回的可选值将包含转换后的值,否则返回 `nil`。如果在编译时就能确定转换一定会成功或是失败,则会导致编译错。
`as!` 运算符执行强制类型转换,返回目标类型的非可选值。如果转换失败,则会导致运行时错误。表达式 `x as T` 效果等同于 `(x as? T)!`
`as!` 运算符执行强制类型转换,返回目标类型的非可选值。如果转换失败,则会导致运行时错误。表达式 `x as! T` 效果等同于 `(x as? T)!`
关于类型转换的更多内容和例子,请参阅 [类型转换](../chapter2/19_Type_Casting.html)。
关于类型转换的更多内容和例子,请参阅 [类型转换](../chapter2/19_Type_Casting.md)。
<a name="type-casting-operator"></a>
> 类型转换运算符语法
> *类型转换运算符* → **is** [*类型*](03_Types.html#type)
> *类型转换运算符* → **as** [*类型*](03_Types.html#type)
> *类型转换运算符* → **is** **?** [*类型*](03_Types.html#type)
> *类型转换运算符* → **as** **!** [*类型*](03_Types.html#type)
> *类型转换运算符* → **is** [*类型*](03_Types.md#type)
> *类型转换运算符* → **as** [*类型*](03_Types.md#type)
> *类型转换运算符* → **as** **?** [*类型*](03_Types.md#type)
> *类型转换运算符* → **as** **!** [*类型*](03_Types.md#type)
<a name="primary_expressions"></a>
## 基本表达式
基本表达式是最基本的表达式。 它们可以跟前缀表达式、二元表达式、后缀表达式以及其他基本表达式组合使用。
基本表达式是最基本的表达式。它们可以单独使用,也可以跟前缀表达式、二元表达式、后缀表达式组合使用。
> 基本表达式语法
<a name="primary-expression"></a>
@ -217,6 +220,7 @@ f(x as Any)
> *基本表达式* → [*圆括号表达式*](#parenthesized-expression)
> *基本表达式* → [*隐式成员表达式*](#implicit-member-expression)
> *基本表达式* → [*通配符表达式*](#wildcard-expression)
> *基本表达式* → [*选择器表达式*](#selector-expression)
<a name="literal_expression"></a>
### 字面量表达式
@ -225,17 +229,19 @@ f(x as Any)
字面量 | 类型 | 值
:------------- | :---------- | :----------
`__FILE__` | `String` | 所在的文件名
`__LINE__` | `Int` | 所在的行数
`__COLUMN__` | `Int` | 所在的列数
`__FUNCTION__` | `String` | 所在的声明的名字
`#file` | `String` | 所在的文件名
`#line` | `Int` | 所在的行数
`#column` | `Int` | 所在的列数
`#function` | `String` | 所在的声明的名字
对于 `__FUNCTION__`,在函数中会返回当前函数的名字,在方法中会返回当前方法的名字,在属性的存取器中会返回属性的名字,在特殊的成员如 `init``subscript` 中会返回这个关键字的名字,在某个文件中会返回当前模块的名字
`#line`除了上述含义外,还有另一种含义。当它出现在单独一行时,会被理解成行控制语句,请参阅[线路控制语句](../chapter3/10_Statements.md#线路控制语句)
`__FUNCTION__` 作为函数或者方法的默认参数值时,该字面量的值取决于函数或方法调用时所处的环境
对于 `function`,在函数中会返回当前函数的名字,在方法中会返回当前方法的名字,在属性的存取器中会返回属性的名字,在特殊的成员如 `init``subscript` 中会返回这个关键字的名字,在某个文件中会返回当前模块的名字
`#function` 作为函数或者方法的默认参数值时,该字面量的值取决于函数或方法的调用环境。
```swift
func logFunctionName(string: String = __FUNCTION__) {
func logFunctionName(string: String = #function) {
print(string)
}
func myFunction() {
@ -248,7 +254,7 @@ myFunction() // 打印 “myFunction()”
> [`值 1`, `值 2`, `...`]
数组中的最后一个表达式可以紧跟一个逗号。数组字面量的类型是 `[T]`,这个 `T` 就是数组中元素的类型。如果数组中包含多种类型,`T` 则是跟这些类型最近的的公共父类型。空数组字面量由一组方括号定义,可用来创建特定类型的空数组。
数组中的最后一个表达式可以紧跟一个逗号。数组字面量的类型是 `[T]`,这个 `T` 就是数组中元素的类型。如果数组中包含多种类型,`T` 则是跟这些类型最近的的公共父类型。空数组字面量由一组方括号定义,可用来创建特定类型的空数组。
```swift
var emptyArray: [Double] = []
@ -258,7 +264,7 @@ var emptyArray: [Double] = []
> [`键 1` : `值 1`, `键 2` : `值 2`, `...`]
字典中的最后一个表达式可以紧跟一个逗号。字典字面量的类型是 `[Key : Value]``Key` 表示键的类型,`Value` 表示值的类型。如果字典中包含多种类型,那么 `Key` 表示的类型则为所有键最接近的公共父类型,`Value` 也是同样如此。一个空的字典字面量由方括号中加一个冒号组成(`[:]`),从而与空数组字面量区分开,可以使用空字典字面量来创建特定类型的字典。
字典中的最后一个表达式可以紧跟一个逗号。字典字面量的类型是 `[Key : Value]``Key` 表示键的类型,`Value` 表示值的类型。如果字典中包含多种类型,那么 `Key` 表示的类型则为所有键最接近的公共父类型,`Value` 与之相似。一个空的字典字面量由方括号中加一个冒号组成(`[:]`),从而与空数组字面量区分开,可以使用空字典字面量来创建特定类型的字典。
```swift
var emptyDictionary: [String : Double] = [:]
@ -269,7 +275,7 @@ var emptyDictionary: [String : Double] = [:]
<a name="literal-expression"></a>
> *字面量表达式* → [*字面量*](02_Lexical_Structure.md#literal)
> *字面量表达式* → [*数组字面量*](#array-literal) | [*字典字面量*](#dictionary-literal)
> *字面量表达式* → **\_\_FILE\_\_** | **\_\_LINE\_\_** | **\_\_COLUMN\_\_** | **\_\_FUNCTION\_\_**
> *字面量表达式* → **#file** | **#line** | **#column** | **#function**
<a name="array-literal"></a>
> *数组字面量* → **[** [*数组字面量项列表*](#array-literal-items)<sub>可选</sub> **]**
@ -322,10 +328,14 @@ struct Point {
> self 表达式语法
<a name="self-expression"></a>
> *self 表达式* → **self**
> *self 表达式* → **self** **.** [*标识符*](02_Lexical_Structure.md#identifier)
> *self 表达式* → **self** **[** [*表达式*](#expression) **]**
> *self 表达式* → **self** **.** **init**
> *self 表达式* → **self** | [*self 方法表达式*](#self-method-expression) [*self 下标表达式*](#self-subscript-expression) | [*self 构造器表达式*](#self-initializer-expression)
>
<a name="self-method-expression"></a>
> *self 方法表达式* → **self** **.** [*标识符*](02_Lexical_Structure.md#identifier)
<a name="self-subscript-expression"></a>
> *self 下标表达式* → **self** **[** [*表达式*](#expression) **]**
<a name="self-initializer-expression"></a>
> *self 构造器表达式* → **self** **.** **init**
<a name="superclass_expression"></a>
### 超类表达式
@ -353,7 +363,7 @@ struct Point {
<a name="closure_expression"></a>
### 闭包表达式
闭包表达式会创建一个闭包,在其他语言中也叫匿名函数。跟函数一样,闭包包含了待执行的代码,不同的是闭包还会捕获所在环境中的常量和变量。它的形式如下:
闭包表达式会创建一个闭包,在其他语言中也叫 *lambda*匿名函数。跟函数一样,闭包包含了待执行的代码,不同的是闭包还会捕获所在环境中的常量和变量。它的形式如下:
```swift
{ (parameters) -> return type in
@ -365,9 +375,9 @@ struct Point {
闭包还有几种特殊的形式,能让闭包使用起来更加简洁:
- 闭包可以省略它的参数和返回值的类型。如果省略了参数名和参数类型,也要省略 `in` 关键字。如果被省略的类型无法被编译器推断,那么就会导致编译错误。
- 闭包可以省略参数名,参数会被隐式命名为 `$` 上其索引位置,例如 `$0``$1``$2` 分别表示第一个、第二个、第三个参数,以此类推。
- 如果闭包中只包含一个表达式,那么该表达式的结果就会自动成为闭包的返回值。表达式结果的类型也会被推断为闭包的返回类型。
- 闭包可以省略它的参数和返回值的类型。如果省略了参数名和所有的类型,也要省略 `in` 关键字。如果被省略的类型无法被编译器推断,那么就会导致编译错误。
- 闭包可以省略参数名,参数会被隐式命名为 `$` 上其索引位置,例如 `$0``$1``$2` 分别表示第一个、第二个、第三个参数,以此类推。
- 如果闭包中只包含一个表达式,那么该表达式的结果就会被视为闭包的返回值。表达式结果的类型也会被推断为闭包的返回类型。
下面几个闭包表达式是等价的:
@ -391,11 +401,11 @@ myFunction { $0 + $1 }
#### 捕获列表
默认情况下,闭包会通过强引用捕获所在环境中的常量和变量。你可以通过一个捕获列表来显式指定它的捕获行为。
默认情况下,闭包会捕获附近作用域中的常量和变量,并使用强引用指向它们。你可以通过一个捕获列表来显式指定它的捕获行为。
捕获列表在参数列表之前,由中括号括起来,里面是由逗号分隔的一系列表达式。一旦使用了捕获列表,就必须使用 `in` 关键字,即使省略了参数名、参数类型返回类型。
捕获列表在参数列表之前,由中括号括起来,里面是由逗号分隔的一系列表达式。一旦使用了捕获列表,就必须使用 `in` 关键字,即使省略了参数名、参数类型返回类型。
捕获列表中的条目会在闭包创建时被初始化。每一个条目都会闭包所在环境中的同名常量或者变量初始化。例如下面的代码示例中,捕获列表包含 `a` 而不包含 `b`,这将导致这两个变量具有不同的行为。
捕获列表中的会在闭包创建时被初始化。每一都会闭包附近作用域中的同名常量或者变量的值初始化。例如下面的代码示例中,捕获列表包含 `a` 而不包含 `b`,这将导致这两个变量具有不同的行为。
```swift
var a = 0
@ -412,7 +422,7 @@ closure()
在示例中,变量 `b` 只有一个,然而,变量 `a` 有两个,一个在闭包外,一个在闭包内。闭包内的变量 `a` 会在闭包创建时用闭包外的变量 `a` 的值来初始化,除此之外它们并无其他联系。这意味着在闭包创建后,改变某个 `a` 的值都不会对另一个 `a` 的值造成任何影响。与此相反,闭包内外都是同一个变量 `b`,因此在闭包外改变其值,闭包内的值也会受影响。
如果闭包捕获的值引用语义,则又会有所不同。例如,下面示例中,有两个变量 `x`,一个在闭包外,一个在闭包内,由于它们的值是引用语义,虽然这是两个不同的变量,它们却都引用着同一实例。
如果闭包捕获的值具有引用语义有所不同。例如,下面示例中,有两个变量 `x`,一个在闭包外,一个在闭包内,由于它们的值是引用语义,虽然这是两个不同的变量,它们却都引用着同一实例。
```swift
class SimpleClass {
@ -438,7 +448,7 @@ myFunction { [weak self] in print(self!.title) } // 以弱引用捕获
myFunction { [unowned self] in print(self.title) } // 以无主引用捕获
```
在捕获列表中,也可以使用任意表达式来赋值。该表达式会在闭包被创建时进行求值,闭包会按照指定的引用类型来捕获表达式的值。例如:
在捕获列表中,也可以任意表达式的值绑定到一个常量上。该表达式会在闭包被创建时进行求值,闭包会按照指定的引用类型来捕获表达式的值。例如:
```swift
// 以弱引用捕获 self.parent 并赋值给 parent
@ -471,7 +481,7 @@ myFunction { [weak parent = self.parent] in print(parent!.title) }
<a name="implicit_member_expression"></a>
### 隐式成员表达式
在可以判断出类型的上下文中,隐式成员表达式访问某个类型的成员(例如某个枚举成员或某个类型方法)的简洁方法,形式如下:
若类型可被推断出来,可以使用隐式成员表达式访问某个类型的成员(例如某个枚举成员或某个类型方法),形式如下:
> .`成员名称`
@ -489,7 +499,7 @@ x = .AnotherValue
<a name="parenthesized_expression"></a>
### 圆括号表达式
圆括号表达式由多个逗号分隔的子表达式组成。每个子表达式前面可以有一个标识符,用冒号隔开,其形式如下:
圆括号表达式由圆括号和其中多个逗号分隔的子表达式组成。每个子表达式前面可以有一个标识符,用冒号隔开。圆括号表达式形式如下:
> (`标识符 1` : `表达式 1`, `标识符 2` : `表达式 2`, `...`)
@ -506,7 +516,7 @@ x = .AnotherValue
<a name="wildcard_expression"></a>
### 通配符表达式
通配符表达式用来忽略传递进来的某个参数。例如下面的代码中,`10`传递`x``20` 被忽略:
通配符表达式可以在赋值过程中显式忽略某个值。例如下面的代码中,`10`赋值`x``20` 被忽略:
```swift
(x, _) = (10, 20)
@ -517,12 +527,51 @@ x = .AnotherValue
<a name="wildcard-expression"></a>
> *通配符表达式* → **_**
<a name="selector_expression"></a>
### 选择器表达式
可通过选择器表达式来获取引用 Objective-C 方法的选择器。
> \#selector(方法名)
方法名必须是存在于 Objective-C 运行时中的方法的引用。选择器表达式的返回值是一个 `Selector` 类型的实例。例如:
```swift
class SomeClass: NSObject {
@objc(doSomethingWithInt:)
func doSomething(x: Int) { }
}
let x = SomeClass()
let selector = #selector(x.doSomething(_:))
```
具有相同方法名但类型不同的方法可以使用 `as` 操作符来区分:
```swift
extension SomeClass {
@objc(doSomethingWithString:)
func doSomething(x: String) { }
}
let anotherSelector = #selector(x.doSomething(_:) as (String) -> Void)
```
由于选择器是在编译时创建的,因此编译器可以检查方法是否存在,以及方法是否在运行时暴露给了 Objective-C 。
> 注意
> 虽然方法名是个表达式,但是它不会被求值。
更多关于如何在 Swift 代码中使用选择器来与 Objective-C API 进行交互的信息,请参阅 [*Using Swift with Cocoa and Objective-C*](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216) 中的 [*Objective-C Selectors*](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-ID59) 部分。
> 选择器表达式语法
<a name="selector-expression"></a>
> *选择器表达式* → __#selector__ **(** [*表达式*](#expression) **)**
<a name="postfix_expressions"></a>
## 后缀表达式
后缀表达式就是在某个表达式的后面加上后缀运算符。严格地讲,每个基本表达式也是一个后缀表达式。
后缀表达式就是在某个表达式的后面运用后缀运算符或其他后缀语法。从语法构成上来看,基本表达式也是后缀表达式。
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.html) 和 [高级运算符](../chapter2/25_Advanced_Operators.html)。
关于这些运算符的更多信息,请参阅 [基本运算符](../chapter2/02_Basic_Operators.md) 和 [高级运算符](../chapter2/25_Advanced_Operators.md)。
关于 Swift 标准库提供的运算符的更多信息,请参阅 [*Swift Standard Library Operators Reference*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_StandardLibrary_Operators/index.html#//apple_ref/doc/uid/TP40016054)。
@ -582,12 +631,11 @@ myData.someMethod {$0 == 13}
> `表达式`.init(`构造器参数`)
你可以在函数调用表达式中使用构造器表达式来初始化某个类型的新实例。也可以使用构造器表达式来代理超类构造器。
你可以在函数调用表达式中使用构造器表达式来初始化某个类型的新实例。也可以使用构造器表达式来代理超类构造器。
```swift
class SomeSubClass: SomeSuperClass {
init() {
override init() {
// 此处为子类构造过程
super.init()
}
@ -606,7 +654,6 @@ print(oneTwoThree)
如果通过名字来指定某个类型,可以不用构造器表达式而直接使用类型的构造器。在其他情况下,你必须使用构造器表达式。
```swift
let s1 = SomeType.init(data: 3) // 有效
let s2 = SomeType(data: 1) // 有效
@ -617,12 +664,13 @@ let s3 = someValue.dynamicType.init(data: 7) // 有效
> 构造器表达式语法
<a name="initializer-expression"></a>
> *构造器表达式* → [*后缀表达式*](postfix-expression) **.** **init**
> *构造器表达式* → [*后缀表达式*](#postfix-expression) **.** **init**
> *构造器表达式* → [*后缀表达式*](#postfix-expression) **.** **init** **(** [*参数名称*](#argument-names) **)**
<a name="explicit_member_expression"></a>
### 显式成员表达式
显式成员表达式允许我们访问命名类型、元组或者模块的成员,形式如下:
显式成员表达式允许我们访问命名类型、元组或者模块的成员,形式如下:
> `表达式`.`成员名`
@ -636,7 +684,7 @@ let c = SomeClass()
let y = c.someProperty // 访问成员
```
元组的成员会根据表示它们出现顺序的整数来隐式命名,以 0 开始,例如:
元组的成员会隐式地根据表示它们出现顺序的整数来命名,以 0 开始,例如:
```swift
var t = (10, 20, 30)
@ -646,22 +694,56 @@ t.0 = t.1
对于模块的成员来说,只能直接访问顶级声明中的成员。
为了区分只有参数名有所不同的方法或构造器,在圆括号中写出参数名,参数名后紧跟一个冒号,对于没有参数名的参数,使用下划线代替参数名。而对于重载方法,则需使用类型标注进行区分。例如:
```swift
class SomeClass {
func someMethod(x: Int, y: Int) {}
func someMethod(x: Int, z: Int) {}
func overloadedMethod(x: Int, y: Int) {}
func overloadedMethod(x: Int, y: Bool) {}
}
let instance = SomeClass()
let a = instance.someMethod // 有歧义
let b = instance.someMethod(_:y:) // 无歧义
let d = instance.overloadedMethod // 有歧义
let d = instance.overloadedMethod(_:y:) // 有歧义
let d: (Int, Bool) -> Void = instance.overloadedMethod(_:y:) // 无歧义
```
如果点号(`.`)出现在行首,它会被视为显式成员表达式的一部分,而不是隐式成员表达式的一部分。例如如下代码所展示的被分为多行的链式方法调用:
```swift
let x = [10, 3, 20, 15, 4]
.sort()
.filter { $0 > 5 }
.map { $0 * 100 }
```
> 显式成员表达式语法
<a name="explicit-member-expression"></a>
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*十进制数字*](02_Lexical_Structure.md#decimal-digit)
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*标识符*](02_Lexical_Structure.html#identifier) [*泛型实参子句*](08_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub>
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*标识符*](02_Lexical_Structure.md#identifier) [*泛型实参子句*](08_Generic_Parameters_and_Arguments.md#generic-argument-clause)<sub>可选</sub><br/>
> *显式成员表达式* → [*后缀表达式*](#postfix-expression) **.** [*标识符*](02_Lexical_Structure.md#identifier) **(** [*参数名称*](#argument-names) **)**
>
<a name="argument-names"></a>
> *参数名称* → [*参数名*](#argument-name) [*参数名称*](#argument-names)<sub>可选</sub><br/>
<a name="argument-name"></a>
> *参数名* → [*标识符*](02_Lexical_Structure.md#identifier) **:**
<a name="postfix_self_expression"></a>
### 后缀 self 表达式
后缀 `self` 表达式由某个表达式紧跟 `.self` 组成,形式如下:
后缀 `self` 表达式由某个表达式或类型名紧跟 `.self` 组成,形式如下:
> `表达式`.self
> `类型`.self
第一种形式返回表达式的值。例如:`x.self` 返回 `x`
第二种形式返回表示对应类型的值。我们可以用它来动态地获取某个实例的类型。例如,`SomeClass.self` 会返回 `SomeClass` 类型本身,你可以将其传递给相应函数或者方法作为参数。
第二种形式返回相应的类型。我们可以用它来获取某个实例的类型作为一个值来使用。例如,`SomeClass.self` 会返回 `SomeClass` 类型本身,你可以将其传递给相应函数或者方法作为参数。
> 后缀 self 表达式语法
<a name="postfix-self-expression"></a>
@ -670,11 +752,11 @@ t.0 = t.1
<a name="dynamic_type_expression"></a>
### dynamicType 表达式
`dynamicType` 表达式由某个表达式紧跟 `.dynamicType` 组成,形式如下:
`dynamicType` 表达式由某个表达式紧跟 `.dynamicType` 组成,形式如下:
> `表达式`.dynamicType
上述形式中的表达式不能是类型名。`dynamicType` 表达式会返回某个实例在运行时的类型,具体请看下面的子:
上述形式中的表达式不能是类型名。`dynamicType` 表达式会返回某个实例在运行时的类型,具体请看下面的子:
```swift
class SomeBaseClass {
@ -705,7 +787,7 @@ someInstance.dynamicType.printClassName()
> `表达式`[`索引表达式`]
要获取下标表达式的值,可将索引表达式作为下标表达式的参数调用表达式类型的下标 getter。下标 setter 的调用方式与之一样。
要获取下标表达式的值,可将索引表达式作为下标表达式的参数调用下标 getter。下标 setter 的调用方式与之一样。
关于下标的声明,请参阅 [协议下标声明](05_Declarations.md#protocol_subscript_declaration)。
@ -745,11 +827,11 @@ someDictionary["a"]![0] = 100
> `表达式`?
后缀 `?` 根据表达式生成可选链表达式而不会改变表达式的值。
后缀 `?` 运算符会根据表达式生成可选链表达式而不会改变表达式的值。
如果某个后缀表达式包含可选链表达式,那么它的执行过程会比较特殊。如果该可选链表达式的值是 `nil`,整个后缀表达式会直接返回 `nil`。如果该可选链表达式的值不是 `nil`,则返回可选链表达式解包后的值,并用于后缀表达式中剩余的表达式。在这两种情况下,整个后缀表达式的值都会是可选类型。
如果某个后缀表达式包含可选链表达式,那么它的执行过程会比较特殊。如果该可选链表达式的值是 `nil`,整个后缀表达式会直接返回 `nil`。如果该可选链表达式的值不是 `nil`,则返回可选链表达式解包后的值,并将该值用于后缀表达式中剩余的表达式。在这两种情况下,整个后缀表达式的值都会是可选类型。
如果某个后缀表达式中包含了可选链表达式,那么只有最外层的表达式会返回一个可选类型。例如,在下面的例子中,如果 `c` 不是 `nil`,那么它的值会被解包,然后通过 `.property` 访问它的属性,接着进一步通过 `.performAction()` 调用相应方法。整个 `c?.property.performAction()` 表达式返回一个可选类型的值。
如果某个后缀表达式中包含了可选链表达式,那么只有最外层的表达式会返回一个可选类型。例如,在下面的例子中,如果 `c` 不是 `nil`,那么它的值会被解包,然后通过 `.property` 访问它的属性,接着进一步通过 `.performAction()` 调用相应方法。整个 `c?.property.performAction()` 表达式返回一个可选类型的值,而不是多重可选类型
```swift
var c: SomeClass?

File diff suppressed because it is too large Load Diff

View File

@ -100,7 +100,7 @@ protocol MyProtocol {
protocol MyRenamedProtocol {
// 这里是协议定义
}
@available(*, unavailable, renamed="MyRenamedProtocol")
typealias MyProtocol = MyRenamedProtocol
```
@ -109,7 +109,7 @@ typealias MyProtocol = MyRenamedProtocol
如果 `available` 特性除了平台名称参数外,只指定了一个 `introduced` 参数,那么可以使用以下简写语法代替:
> @available(`平台名称` `版本号`, *)
> @available(`平台名称` `版本号`, * )
`available` 特性的简写语法可以简明地表达出声明在多个平台上的可用性。尽管这两种形式在功能上是相同的,但请尽可能地使用简写语法形式。
@ -122,13 +122,13 @@ class MyClass {
`objc`
该特性用于修饰任何可以在 Objective-C 中表示的声明。比如,非嵌套类、协议、非泛型枚举(仅限原始值为整型的枚举)、类和协议中的属性和方法(包括存取方法)、构造器、析构器以及下标。`objc` 特性告诉编译器这个声明可以在 Objective-C 代码中使用。
该特性用于修饰任何可以在 Objective-C 中表示的声明。比如,非嵌套类、协议、非泛型枚举(仅限原始值为整型的枚举)、类和协议中的属性和方法(包括存取方法)、构造器、析构器以及下标运算符`objc` 特性告诉编译器这个声明可以在 Objective-C 代码中使用。
标有 `objc` 特性的类必须继承自 Objective-C 中定义的类。如果你将 `objc` 特性应用于一个类或协议,它也会隐式地应用于类或协议中兼容 Objective-C 的成员。对于标记了 `objc` 特性的类,编译器会隐式地为它的子类添加 `objc` 特性。标记了 `objc` 特性的协议不能继承没有标记 `objc` 的协议。
如果你将 `objc` 特性应用于枚举,每一个枚举用例都会以枚举名称和用例名称组合的方式暴露在 Objective-C 代码中。例如,在 `Planet` 枚举中有一个名为 `Venus` 的用例,该用例暴露在 Objective-C 代码中时叫做 `PlanetVenus`
`objc` 特性有一个可选的参数,由标识符构成。当你想把 `objc` 所修饰的实体以一个不同的名字暴露给 Objective-C 时,你就可以使用这个特性参数。你可以使用这个参数来命名类、协议、方法、存取方法以及构造器。下面的例子把 `ExampleClass` 中的 `enabled` 属性的取值方法暴露给 Objective-C名字是 `isEnabled`,而不是它原来的属性名。
`objc` 特性有一个可选的参数,由标识符构成。当你想把 `objc` 所修饰的实体以一个不同的名字暴露给 Objective-C 时,你就可以使用这个特性参数。你可以使用这个参数来命名类、枚举类型、枚举用例、协议、方法、存取方法以及构造器。下面的例子把 `ExampleClass` 中的 `enabled` 属性的取值方法暴露给 Objective-C名字是 `isEnabled`,而不是它原来的属性名。
```swift
@objc

View File

@ -239,7 +239,7 @@
> *声明* → [*构造器声明*](../chapter3/05_Declarations.html#initializer_declaration)
> *声明* → [*析构器声明*](../chapter3/05_Declarations.html#deinitializer_declaration)
> *声明* → [*扩展声明*](../chapter3/05_Declarations.html#extension_declaration)
> *声明* → [*下标脚本声明*](../chapter3/05_Declarations.html#subscript_declaration)
> *声明* → [*下标声明*](../chapter3/05_Declarations.html#subscript_declaration)
> *声明* → [*运算符声明*](../chapter3/05_Declarations.html#operator_declaration)
> *声明(Declarations)集* → [*声明*](../chapter3/05_Declarations.html#declaration) [*声明(Declarations)集*](../chapter3/05_Declarations.html#declarations) _可选_
@ -373,7 +373,7 @@
> *协议成员声明* → [*协议属性声明*](../chapter3/05_Declarations.html#protocol_property_declaration)
> *协议成员声明* → [*协议方法声明*](../chapter3/05_Declarations.html#protocol_method_declaration)
> *协议成员声明* → [*协议构造器声明*](../chapter3/05_Declarations.html#protocol_initializer_declaration)
> *协议成员声明* → [*协议下标脚本声明*](../chapter3/05_Declarations.html#protocol_subscript_declaration)
> *协议成员声明* → [*协议下标声明*](../chapter3/05_Declarations.html#protocol_subscript_declaration)
> *协议成员声明* → [*协议关联类型声明*](../chapter3/05_Declarations.html#protocol_associated_type_declaration)
> *协议成员声明(Declarations)集* → [*协议成员声明*](../chapter3/05_Declarations.html#protocol_member_declaration) [*协议成员声明(Declarations)集*](../chapter3/05_Declarations.html#protocol_member_declarations) _可选_
@ -394,8 +394,8 @@
<!-- -->
> 协议下标脚本声明语法
> *协议下标脚本声明* → [*下标脚本头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标脚本结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
> 协议下标声明语法
> *协议下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
<!-- -->
@ -426,12 +426,12 @@
<!-- -->
> 下标脚本声明语法
> *下标脚本声明* → [*下标脚本头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标脚本结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*代码块*](../chapter3/05_Declarations.html#code_block)
> *下标脚本声明* → [*下标脚本头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标脚本结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter块*](../chapter3/05_Declarations.html#getter_setter_block)
> *下标脚本声明* → [*下标脚本头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标脚本结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
> *下标脚本头(Head)* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ [*声明修改器(declaration-modifiers)*](TODO) _可选_ **subscript** [*参数从句*](../chapter3/05_Declarations.html#parameter_clause)
> *下标脚本结果(Result)* → **->** [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ [*类型*](../chapter3/03_Types.html#type)
> 下标声明语法
> *下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*代码块*](../chapter3/05_Declarations.html#code_block)
> *下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter块*](../chapter3/05_Declarations.html#getter_setter_block)
> *下标声明* → [*下标头(Head)*](../chapter3/05_Declarations.html#subscript_head) [*下标结果(Result)*](../chapter3/05_Declarations.html#subscript_result) [*getter-setter关键字(Keyword)块*](../chapter3/05_Declarations.html#getter_setter_keyword_block)
> *下标头(Head)* → [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ [*声明修改器(declaration-modifiers)*](TODO) _可选_ **subscript** [*参数从句*](../chapter3/05_Declarations.html#parameter_clause)
> *下标结果(Result)* → **->** [*属性(Attributes)集*](../chapter3/06_Attributes.html#attributes) _可选_ [*类型*](../chapter3/03_Types.html#type)
<!-- -->

View File

@ -9,10 +9,12 @@
> 2.0
> 翻译+校对:[littledogboy](https://github.com/littledogboy)
> 2.2
> 翻译:[chenmingbiao](https://github.com/chenmingbiao)
本页包含内容:
- [循环语句](#loop_statements)
- [For 语句](#for_statements)
- [For-In 语句](#for-in_statements)
- [While 语句](#while_statements)
- [Repeat-While 语句](#repeat-while_statements)
@ -26,15 +28,15 @@
- [Continue 语句](#continue_statement)
- [Fallthrough 语句](#fallthrough_statements)
- [Return 语句](#return_statements)
- [Available 语句](#availability_statements)
- [Throw 语句](#throw_statements)
- [Defer 语句](#defer_statements)
- [Do 语句](#do_statements)
- [编译器控制语句](#compiler_control_statements)
- [编译配置语句](#build_config_statements)
- [源代码控制语句](#line_control_statements)
- [控制语句](#line_control_statements)
- [可用性条件](#availability_condition)
在 Swift 中,有三种类型的语句:简单语句、编译器控制语句和控制流语句。简单语句是最常见的,用于构造表达式或者声明。编译器控制语句允许程序改变编译器的行为,包含编译配置语句和线路控制语句。
在 Swift 中,有三种类型的语句:简单语句、编译器控制语句和控制流语句。简单语句是最常见的,用于构造表达式或者声明。编译器控制语句允许程序改变编译器的行为,包含编译配置语句和控制语句。
控制流语句则用于控制程序执行的流程Swift 中有多种类型的控制流语句循环语句、分支语句和控制转移语句。循环语句用于重复执行代码块分支语句用于执行满足特定条件的代码块控制转移语句则用于改变代码的执行顺序。另外Swift 提供了 `do` 语句,用于构建局部作用域,还用于错误的捕获和处理;还提供了 `defer` 语句,用于退出当前作用域之前执行清理操作。
@ -57,53 +59,20 @@
<a name="loop_statements"></a>
## 循环语句
循环语句会根据特定的循环条件来重复执行代码块。Swift 提供种类型的循环语句:`for` 语句、`for-in` 语句、`while` 语句和 `repeat-while` 语句。
循环语句会根据特定的循环条件来重复执行代码块。Swift 提供种类型的循环语句:`for-in` 语句、`while` 语句和 `repeat-while` 语句。
通过 `break` 语句和 `continue` 语句可以改变循环语句的控制流。有关这两条语句,详情参见 [Break 语句](#break_statement) 和 [Continue 语句](#continue_statement)。
> 循环语句语法
<a name="loop-statement"></a>
> *循环语句* → [*for 语句*](#for-statement)
> *循环语句* → [*for-in 语句*](#for-in-statement)
> *循环语句* → [*while 语句*](#while-statement)
> *循环语句* → [*repeat-while 语句*](#repeat-while-statement)
<a name="for_statements"></a>
### For 语句
`for` 语句只有在循环条件为真时重复执行代码块,同时计数器递增。
`for` 语句的形式如下:
```swift
for 初始化; 条件; 增量 {
语句
}
```
初始化、条件和增量语句之间必须以分号相隔,循环体中的语句必须以花括号包裹。
`for` 语句的执行流程如下:
1. 初始化只会被执行一次,通常用于声明和初始化在接下来的循环中需要使用的变量。
2. 判断条件的值。如果为 `true`,循环体中的语句将会被执行,然后转到第 3 步;如果为 `false`,循环体中的语句以及增量语句都不会被执行,`for` 语句至此执行完毕。
3. 执行增量语句,然后重复第 2 步。
在初始化语句中定义的变量仅在 `for` 循环的作用域内有效。
条件的结果必须符合 `BooleanType` 协议。
> for 语句语法
<a name="for-statement"></a>
> *for 语句* → **for** [*for初始条件*](#for-init)<sub>可选</sub> **;** [*表达式*](04_Expressions.md#expression)<sub>可选</sub> **;** [*表达式*](04_Expressions.md#expression)<sub>可选</sub> [*代码块*](05_Declarations.md#code-block)
> *for语句* → **for** **(** [*for初始条件*](#for-init)<sub>可选</sub> **;** [*表达式*](04_Expressions.md#expression)<sub>可选</sub> **;** [*表达式*](04_Expressions.md#expression)<sub>可选</sub> **)** [*代码块*](05_Declarations.md#code-block)
<a name="for-init"></a>
> *for 初始条件* → [*变量声明*](05_Declarations.md#variable-declaration) | [*表达式列表*](04_Expressions.md#expression-list)
<a name="for-in_statements"></a>
### For-In 语句
`for-in` 语句会为集合(或符合 `Sequence` 协议的任意类型)中的每一项执行一次代码块。
`for-in` 语句会为集合(或实现了 `SequenceType` 协议的任意类型)中的每一项执行一次代码块。
`for-in` 语句的形式如下:
@ -113,7 +82,7 @@ for 项 in 集合 {
}
```
`for-in` 语句在循环开始前会调用集合表达式的 `generate()` 方法来获取一个符合 `Generator` 协议的类型的值。接下来循环开始,反复调用该值的 `next()` 方法。如果其返回值不是 `None`,它将会被赋给“项”,然后执行循环体语句,执行完毕后回到循环开始处,继续重复这一过程;否则,既不会赋值也不会执行循环体语句,`for-in` 语句至此执行完毕。
`for-in` 语句在循环开始前会调用集合表达式的 `generate()` 方法来获取一个实现了 `GeneratorType` 协议的类型的值。接下来循环开始,反复调用该值的 `next()` 方法。如果其返回值不是 `None`,它将会被赋给“项”,然后执行循环体语句,执行完毕后回到循环开始处,继续重复这一过程;否则,既不会赋值也不会执行循环体语句,`for-in` 语句至此执行完毕。
> for-in 语句语法
<a name="for-in-statement"></a>
@ -304,9 +273,9 @@ default:
`switch` 语句会先计算控制表达式的值,然后与每一个 `case` 的模式进行匹配。如果匹配成功,程序将会执行对应的 `case` 中的语句。另外,每一个 `case` 都不能为空,也就是说在每一个 `case` 中必须至少有一条语句。如果你不想在匹配到的 `case` 中执行代码,只需在该 `case` 中写一条 `break` 语句即可。
可以用作控制表达式的值是十分灵活的。除了标量类型外,如 `Int``Character`,你可以使用任何类型的值,包括浮点数、字符串、元组、自定义类型的实例和可选类型,甚至是指定的 `Range` 或枚举类型中的成员值。关于如何在 `switch` 语句中使用这些类型,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章中的 [Switch](../chapter2/05_Control_Flow.html#switch)。
可以用作控制表达式的值是十分灵活的。除了标量类型外,如 `Int``Character`,你可以使用任何类型的值,包括浮点数、字符串、元组、自定义类型的实例和可选类型。控制表达式的值还可以用来匹配枚举类型中的成员值或是检查该值是否包含在指定的 `Range` 。关于如何在 `switch` 语句中使用这些类型,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章中的 [Switch](../chapter2/05_Control_Flow.html#switch)。
每个 `case` 的模式后面可以有一个 `where` 子句。`where` 子句由 `where` 关键字紧跟一个提供额外测试条件的表达式组成。因此,当且仅当控制表达式匹配一个 `case` 的模式且 `where` 子句的表达式为真时,`case` 中的语句才会被执行。在下面的例子中,控制表达式只会匹配包含两个相等元素的元组,例如 `(1, 1)`
每个 `case` 的模式后面可以有一个 `where` 子句。`where` 子句由 `where` 关键字紧跟一个提供额外条件的表达式组成。因此,当且仅当控制表达式匹配一个 `case` 的模式且 `where` 子句的表达式为真时,`case` 中的语句才会被执行。在下面的例子中,控制表达式只会匹配包含两个相等元素的元组,例如 `(1, 1)`
```swift
case let (x, y) where x == y:
@ -318,11 +287,11 @@ case let (x, y) where x == y:
`switch` 语句中 `case` 的匹配顺序和源代码中的书写顺序保持一致。因此,当多个模式都能匹配控制表达式时,只有第一个匹配的 `case` 中的代码会被执行。
#### Switch 语句必须是详尽的
#### Switch 语句不能有遗漏
在 Swift 中,`switch` 语句中控制表达式的每一个可能的值都必须至少有一个 `case` 与之对应。在某些无法面面俱到的情况下(例如,表达式的类型是 `Int`),你可以使用 `default` 分支满足该要求。
#### 不存在隐式落
#### 不存在隐式落
当匹配到的 `case` 中的代码执行完毕后,`switch` 语句会直接退出,而不会继续执行下一个 `case` 。这就意味着,如果你想执行下一个 `case`,需要显式地在当前 `case` 中使用 `fallthrough` 语句。关于 `fallthrough` 语句的更多信息,请参阅 [Fallthrough 语句](#fallthrough_statements)。
@ -352,7 +321,7 @@ case let (x, y) where x == y:
你可以在循环语句或 `switch` 语句前面加上标签,它由标签名和紧随其后的冒号(`:`)组成。在 `break``continue` 后面跟上标签名可以显式地在循环语句或 `switch` 语句中改变相应的控制流。关于这两条语句用法,请参阅 [Break 语句](#break_statement) 和 [Continue 语句](#continue_statement)。
标签的作用域在该标签所标记的语句内。可以使用带标签的语句,但只要使用它,在作用域内需保证标签名唯一。
标签的作用域在该标签所标记的语句内。可以嵌套使用带标签的语句,但标签名必须唯一。
关于使用带标签的语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章中的 [带标签的语句](../chapter2/05_Control_Flow.md#labeled_statements)。
@ -380,16 +349,16 @@ case let (x, y) where x == y:
<a name="break_statement"></a>
### Break 语句
`break` 语句用于终止循环语句或 `switch` 语句的执行。使用 `break` 语句时,可以只写 `break` 这个关键词,也可以在 `break` 后面跟上标签名,像下面这样:
`break` 语句用于终止循环语句`if` 语句`switch` 语句的执行。使用 `break` 语句时,可以只写 `break` 这个关键词,也可以在 `break` 后面跟上标签名,像下面这样:
> break
> break `标签名`
`break` 语句后面带标签名时,可用于终止由这个标签标记的循环语句或 `switch` 语句的执行。
`break` 语句后面带标签名时,可用于终止由这个标签标记的循环语句`if` 语句`switch` 语句的执行。
而只写 `break` 时,则会终止 `switch` 语句或包含 `break` 语句的最内层循环的执行。
而只写 `break` 时,则会终止 `switch` 语句或 `break` 语句所属的最内层循环语句的执行。不能使用 `break` 语句来终止未使用标签的 `if` 语句。
在这两种情况,控制权都会被传递给循环语句或 `switch` 语句后面的第一行语句。
无论哪种情况,控制权都会被转移给被终止的控制流语句后面的第一行语句。
关于使用 `break` 语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章的 [Break](../chapter2/05_Control_Flow.md#break) 和 [带标签的语句](../chapter2/05_Control_Flow.md#labeled_statements)。
@ -407,9 +376,9 @@ case let (x, y) where x == y:
`continue` 语句后面带标签名时,可用于终止由这个标签标记的循环中当前迭代的执行。
而当只写 `continue` 时,可用于终止上下文中包含 `continue` 语句的最内层循环中当前迭代的执行。
而当只写 `continue` 时,可用于终止 `continue` 语句所属的最内层循环中当前迭代的执行。
在这两种情况下,控制权都会被传递给循环外面的第一行语句。
在这两种情况下,控制权都会被转移给循环语句的条件语句。
`for` 语句中,`continue` 语句执行后,增量表达式还是会被计算,这是因为每次循环体执行完毕后,增量表达式都会被计算。
@ -424,7 +393,7 @@ case let (x, y) where x == y:
`fallthrough` 语句用于在 `switch` 语句中转移控制权。`fallthrough` 语句会把控制权从 `switch` 语句中的一个 `case` 转移到下一个 `case`。这种控制权转移是无条件的,即使下一个 `case` 的模式与 `switch` 语句的控制表达式的值不匹配。
`fallthrough` 语句可出现在 `switch` 语句中的任意 `case` 中,但不能出现在最后一个 `case` 中。同时,`fallthrough` 语句也不能把控制权转移到使用了可选绑定的 `case`
`fallthrough` 语句可出现在 `switch` 语句中的任意 `case` 中,但不能出现在最后一个 `case` 中。同时,`fallthrough` 语句也不能把控制权转移到使用了绑定的 `case`
关于在 `switch` 语句中使用 `fallthrough` 语句的例子,请参阅 [控制流](../chapter2/05_Control_Flow.md) 一章的 [控制转移语句](../chapter2/05_Control_Flow.md#control_transfer_statements)。
@ -435,70 +404,30 @@ case let (x, y) where x == y:
<a name="return_statements"></a>
### Return 语句
`return` 语句用于在函数或方法的实现中将控制权转移调用,接着程序将会从调用者的位置继续向下执行。
`return` 语句用于在函数或方法的实现中将控制权转移调用函数或方法,接着程序将会从调用位置继续向下执行。
使用 `return` 语句时,可以只写 `return` 这个关键词,也可以在 `return` 后面跟上表达式,像下面这样:
> return
> return `表达式`
`return` 语句后面带表达式时,表达式的值将会返回给调用。如果表达式的值的类型与函数或者方法声明的返回类型不匹配Swift 则会在返回表达式的值之前将表达式的值的类型转换为返回类型。
`return` 语句后面带表达式时,表达式的值将会返回给调用函数或方法。如果表达式的值的类型与函数或者方法声明的返回类型不匹配Swift 则会在返回表达式的值之前将表达式的值的类型转换为返回类型。
> 注意
> 正如 [可失败构造器](05_Declarations.md#failable_initializers) 中所描述的,`return nil` 在可失败构造器中用于表明构造失败。
而只写 `return` 时,仅仅是将控制权从该函数或方法转移给调用者,而不返回一个值(也就是说,函数或方法的返回类型为 `Void` 或者说 `()`)。
而只写 `return` 时,仅仅是从该函数或方法中返回,而不返回任何值(也就是说,函数或方法的返回类型为 `Void` 或者说 `()`)。
> return 语句语法
<a name="return-statement"></a>
> *return 语句* → **return** [*表达式*](04_Expressions.html#expression)<sub>可选</sub>
<a name="availability_statements"></a>
### Available 语句
可用性条件可作为 `if``while``guard` 语句的条件,可以在运行时基于特定的平台参数来查询 API 的可用性。
可用性条件的形式如下:
```swift
if #available(平台名称 版本, ..., *) {
如果 API 可用,则执行这部分语句
} else {
如果 API 不可用,则执行这部分语句
}
```
使用可用性条件来执行一个代码块时,取决于使用的接口在运行时是否可用。编译器会根据可用性条件提供的信息以及运行时的平台来决定是否执行相应的代码块。
可用性条件使用一系列逗号分隔的平台名称和版本。使用 `iOS``OSX`,以及 `watchOS` 等作为平台名称,并写上相应的版本号。`*` 参数是必须写的,用于处理未来的潜在平台。可用性条件确保了运行时的平台不低于条件中指定的平台版本时才执行代码块。
与布尔类型的条件不同,不能用逻辑运算符 `&&``||` 合并可用性条件。
> 可用性条件语法
<a name="availability-condition"></a>
> *可用性条件* → **#available** **(** [*可用性参数列表*](#availability-arguments) **)**
<a name="availability-arguments"></a>
> *可用性参数列表* → [*可用性参数*](#availability-argument) | [*可用性参数*](#availability-argument) **,** [*可用性参数列表*](#availability-arguments)
<a name="availability-argument"></a>
> *可用性参数* → [平台名称](#platform-name) [平台版本](#platform-version)
> *可用性条件* → __*__
<a name="platform-name"></a>
> *平台名称* → **iOS** | **iOSApplicationExtension**
> *平台名称* → **OSX** | **OSXApplicationExtension**
> *平台名称* → **watchOS**
<a name="platform-version"></a>
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits)
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits)
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits)
<a name="throw_statements"></a>
### Throw 语句
`throw` 语句出现在抛出函数或者抛出方法体内,或者类型被 `throws` 关键字标记的闭包表达式体内。
`throw` 语句使程序在当前作用域结束执行,并向外围作用域传播错误。抛出的错误会一直传,直到被 `do` 语句的 `catch` 子句处理掉。
`throw` 语句使程序在当前作用域结束执行,并向外围作用域传播错误。抛出的错误会一直传,直到被 `do` 语句的 `catch` 子句处理掉。
`throw` 语句由 `throw` 关键字紧跟一个表达式组成,如下所示:
@ -525,9 +454,9 @@ defer {
}
```
`defer` 语句中的语句无论程序控制如何转移都会执行。这意味着 `defer` 语句可以被使用在以下这些情况,例如关闭文件描述,或者即使抛出了错误也需要执行一些动作
`defer` 语句中的语句无论程序控制如何转移都会执行。在某些情况,例如,手动管理资源时,比如关闭文件描述,或者即使抛出了错误也需要执行一些操作时,就可以使用 `defer` 语句
如果多个 `defer` 语句出现在同一作用域内,那么它们执行的顺序与出现的顺序相反。给定作用域中的第一个 `defer` 语句,会在最后执行,这意味着最后执行`defer` 语句中涉及的资源可以被其他 `defer` 语句清理掉。
如果多个 `defer` 语句出现在同一作用域内,那么它们执行的顺序与出现的顺序相反。给定作用域中的第一个 `defer` 语句,会在最后执行,这意味着代码中最靠后`defer` 语句中引用的资源可以被其他 `defer` 语句清理掉。
```swift
func f() {
@ -550,9 +479,9 @@ f()
<a name="do_statements"></a>
## Do 语句
`do` 语句用于引入一个新的作用域,该作用域中可以含有一个或多个 `catch` 子句,`catch` 子句中定义了一些匹配错误条件的模式。`do` 语句作用域内定义的常量和变量只能在 `do` 语句作用域内使用。
`do` 语句用于引入一个新的作用域,该作用域中可以含有一个或多个 `catch` 子句,`catch` 子句中定义了一些匹配错误条件的模式。`do` 语句作用域内定义的常量和变量只能在 `do` 语句作用域内使用。
Swift 中的 `do` 语句与 C 中限定代码块界限的大括号(`{}`)很相似,并且在程序运行的时候并不会造成系统开销
Swift 中的 `do` 语句与 C 中限定代码块界限的大括号(`{}`)很相似,也并不会降低程序运行时的性能
`do` 语句的形式如下:
@ -567,11 +496,11 @@ do {
}
```
如同 `switch` 语句,编译器会判断 `catch` 子句是否有遗漏。如果 `catch` 子句没有遗漏,则认为错误被处理。否则,错误会自动传到外围作用域,被`catch` 句处理掉或者继续向外抛出,抛出函数必须以 `throws` 关键字声明。
如同 `switch` 语句,编译器会判断 `catch` 子句是否有遗漏。如果 `catch` 子句没有遗漏,则认为错误被处理。否则,错误会自动传到外围作用域,被`catch` 句处理掉或者被用 `throws` 关键字声明的抛出函数继续向外抛出
为了确保错误已经被处理,可以让 `catch` 子句使用匹配所有错误的模式,如通配符模式(`_`)。如果一个 `catch` 子句不指定一种具体模式,`catch` 子句会匹配任何错误,并绑定到名为 `error` 的局部量。有关在 `catch` 子句中使用模式的更多信息,请参阅 [模式](07_Patterns.md)。
为了确保错误已经被处理,可以让 `catch` 子句使用匹配所有错误的模式,如通配符模式(`_`)。如果一个 `catch` 子句不指定一种具体模式,`catch` 子句会匹配任何错误,并绑定到名为 `error` 的局部量。有关在 `catch` 子句中使用模式的更多信息,请参阅 [模式](07_Patterns.md)。
关于如何在 `do` 语句中使用一 `catch` 子句的例子,请参阅 [处理错误](../chapter2/18_Error_Handling.md#handling_errors)。
关于如何在 `do` 语句中使用一系列 `catch` 子句的例子,请参阅 [错误处理](../chapter2/18_Error_Handling.md#handling_errors)。
> do 语句语法
<a name="do-statement"></a>
@ -606,15 +535,18 @@ do {
`if` 语句的条件不同,编译配置的条件是在编译时进行判断的。只有编译配置在编译时判断为 `true` 的情况下,相应的语句才会被编译和执行。
编译配置可以是 `true``false` 的字面量,也可以是使用 `-D` 命令行标志的标识符,或者是下列表格中的任意一个平台测函数。
编译配置可以是 `true``false` 的字面量,也可以是使用 `-D` 命令行标志的标识符,或者是下列表格中的任意一个平台测函数。
| 函数 | 可用参数 |
| --- | --- |
| `os()` | `OSX`, `iOS`, `watchOS`, `tvOS` |
| `os()` | `OSX`, `iOS`, `watchOS`, `tvOS`, `Linux` |
| `arch()` | `i386`, `x86_64`, `arm`, `arm64` |
| `swift()` | `>=` 后跟版本号 |
> 注意
> `arch(arm)` 编译配置在 ARM 64位设备上不会返回 `true`。如果代码在 32 位的 iOS 模拟器上编译,`arch(i386)` 编译配置返回 `true`。
`swift()`(语言版本检测函数)的版本号参数主要由主版本号和次版本号组成并且使用点号(`.`)分隔开,`>=` 和版本号之间不能有空格。
> 注意
> `arch(arm)` 平台检测函数在 ARM 64 位设备上不会返回 `true`。如果代码在 32 位的 iOS 模拟器上编译,`arch(i386)` 平台检测函数会返回 `true`。
你可以使用逻辑操作符 `&&``||``!` 来组合多个编译配置,还可以使用圆括号来进行分组。
@ -631,9 +563,9 @@ do {
```
> 注意
> 即使没有被编译,编译配置中的语句仍然会被解析。
> 即使没有被编译,编译配置中的语句仍然会被解析。然而,唯一的例外是编译配置语句中包含语言版本检测函数:仅当 `Swift` 编译器版本和语言版本检测函数中指定的版本号匹配时,语句才会被解析。这种设定能确保旧的编译器不会尝试去解析新 Swift 版本的语法。
<a name=""></a>
<a name="build-config-statement"></a>
> 编译配置语句语法
<a name="build-configuration-statement"></a>
@ -646,7 +578,8 @@ do {
> *单个编译配置 else 子句* → **#else** [*语句*](#statements)<sub>可选</sub>
<a name="build-configuration"></a>
> *编译配置* → [*平台测函数*](#platform-testing-function)
> *编译配置* → [*平台测函数*](#platform-testing-function)
> *编译配置* → [*语言版本检测函数*](#language-version-testing-function)
> *编译配置* → [*标识符*](02_Lexical_Structure.md#identifier)
> *编译配置* → [*布尔值字面量*](02_Lexical_Structure.md#boolean-literal)
> *编译配置* → **(** [*编译配置*](#build-configuration) **)**
@ -655,33 +588,78 @@ do {
> *编译配置* → [*编译配置*](#build-configuration) **||** [*编译配置*](#build-configuration)
<a name="platform-testing-function"></a>
> *平台测函数* → **os** **(** [*操作系统*](#operating-system) **)**
> *平台测函数* → **arch** **(** [*架构*](#architecture) **)**
> *平台测函数* → **os** **(** [*操作系统*](#operating-system) **)**
> *平台测函数* → **arch** **(** [*架构*](#architecture) **)**
<a name="language-version-testing-function"></a>
> *语言版本检测函数* → **swift** **(** **>=** [*swift版本*](#swift-version) **)**
<a name="operating-system"></a>
> *操作系统* → **OSX** | **iOS** | **watchOS** | **tvOS**
<a name="architecture"></a>
> *架构* → **i386** | **x86_64** | **arm** | **arm64**
> *架构* → **i386** | **x86_64** | **arm** | **arm64**
<a name="swift-version"></a>
> *swift 版本* → [*十进制数字*](02_Lexical_Structure.md#decimal-digit) ­**.** ­[*十进制数字*](02_Lexical_Structure.md#decimal-digit)
<a name="line_control_statements"></a>
### 线路控制语句
### 控制语句
线路控制语句用来为被编译的源代码指定一个与原始行号和文件名不同的行号和文件名。使用线路控制语句可以改变源代码的位置,以便进行分析和调试。
控制语句可以为被编译的源代码指定行号和文件名,从而改变源代码的定位信息,以便进行分析和调试。
线路控制语句形式如下:
控制语句形式如下:
> \#line `行号` `文件名`
线路控制语句会改变之后的字面量表达式 `__LINE__``__FILE__` 的值。`行号` 是一个大于 0 的整形字面量,会改变 `__LINE__` 的值。`文件名` 是一个字符串字面量,会改变 `__FILE__` 的值。
控制语句会改变该语句之后的代码中的字面量表达式 `#line``#file` 所表示的值。`行号` 是一个大于 0 的整形字面量,会改变 `#line` 表达式的值。`文件名` 是一个字符串字面量,会改变 `#file` 表达式的值。
你可以通过 `#line` 语句,即不指定行号和文件名,将源代码的位置重置回默认的行号和文件名。
你可以只写 `#line`,而不指定行号和文件名,从而将源代码的定位信息重置回默认的行号和文件名。
线路控制语句必须独占一行,而且不能是源代码文件的最后一行。
`#line` 标记具有两种含义,作为行控制语句使用时必须独占一行,而且不能是源代码文件的最后一行。否则,它将作为字面量表达式使用,详情请参阅 [字面量表达式](04_Expressions.md#literal_expression)。
> 线路控制语句语法
<a name="line-control-statements"></a>
> *线路控制语句* → **#line**
> *线路控制语句* → **#line** [*行号*](#line-number) [*文件名*](#file-name)
<a name="line-control-statement"></a>
> 行控制语句语法
> *控制语句* → **#line**
> *行控制语句* → **#line** [*行号*](#line-number) [*文件名*](#file-name)
<a name="line-number"></a>
> *行号* → 大于 0 的十进制整数
<a name="file-name"></a>
> *文件名* → [*静态字符串字面量*](02_Lexical_Structure.md#static-string-literal)
<a name="availability_condition"></a>
### 可用性条件
可用性条件可作为 `if``while``guard` 语句的条件,可以在运行时基于特定的平台参数来查询 API 的可用性。
可用性条件的形式如下:
```swift
if #available(平台名称 版本, ..., *) {
如果 API 可用,则执行这部分语句
} else {
如果 API 不可用,则执行这部分语句
}
```
使用可用性条件来执行一个代码块时,取决于使用的 API 在运行时是否可用,编译器会根据可用性条件提供的信息来决定是否执行相应的代码块。
可用性条件使用一系列逗号分隔的平台名称和版本。使用 `iOS``OSX`,以及 `watchOS` 等作为平台名称,并写上相应的版本号。`*` 参数是必须写的,用于处理未来的潜在平台。可用性条件确保了运行时的平台不低于条件中指定的平台版本时才执行代码块。
与布尔类型的条件不同,不能用逻辑运算符 `&&``||` 组合可用性条件。
> 可用性条件语法
<a name="availability-condition"></a>
> *可用性条件* → **#available** **(** [*可用性参数列表*](#availability-arguments) **)**
<a name="availability-arguments"></a>
> *可用性参数列表* → [*可用性参数*](#availability-argument) | [*可用性参数*](#availability-argument) **,** [*可用性参数列表*](#availability-arguments)
<a name="availability-argument"></a>
> *可用性参数* → [平台名称](#platform-name) [平台版本](#platform-version)
> *可用性条件* → __*__
<a name="platform-name"></a>
> *平台名称* → **iOS** | **iOSApplicationExtension**
> *平台名称* → **OSX** | **OSXApplicationExtension**
> *平台名称* → **watchOS**
<a name="platform-version"></a>
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits)
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits)
> *平台版本* → [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits) **.** [十进制数字](02_Lexical_Structure.md#decimal-digits)