format the head style
This commit is contained in:
@ -143,6 +143,12 @@ if let name = optionalName {
|
|||||||
> 把`optionalName`改成`nil`,greeting会是什么?添加一个`else`语句,当`optionalName`是`nil`时给greeting赋一个不同的值。
|
> 把`optionalName`改成`nil`,greeting会是什么?添加一个`else`语句,当`optionalName`是`nil`时给greeting赋一个不同的值。
|
||||||
|
|
||||||
如果变量的可选值是`nil`,条件会判断为`false`,大括号中的代码会被跳过。如果不是`nil`,会将值赋给`let`后面的常量,这样代码块中就可以使用这个值了。
|
如果变量的可选值是`nil`,条件会判断为`false`,大括号中的代码会被跳过。如果不是`nil`,会将值赋给`let`后面的常量,这样代码块中就可以使用这个值了。
|
||||||
|
另一种处理可选值的方法是通过使用 ?? 操作符来提供一个默认值。如果可选值缺失的话,可以使用默认值来代替。
|
||||||
|
```swift
|
||||||
|
let nickName: String? = nil
|
||||||
|
let fullName: String = "John Appleseed"
|
||||||
|
let informalGreeting = "Hi \(nickName ?? fullName)"
|
||||||
|
```
|
||||||
|
|
||||||
`switch`支持任意类型的数据以及各种比较操作——不仅仅是整数以及测试相等。
|
`switch`支持任意类型的数据以及各种比较操作——不仅仅是整数以及测试相等。
|
||||||
|
|
||||||
|
|||||||
@ -374,3 +374,75 @@ let alsoIncrementByTen = incrementByTen
|
|||||||
alsoIncrementByTen()
|
alsoIncrementByTen()
|
||||||
// 返回的值为50
|
// 返回的值为50
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 自动闭包(Autoclosures)
|
||||||
|
一个自动闭包,是一个自动被创建的,用于将一个表达式包装为一个参数,进而传递到函数的闭包。当它被调用的时候,它无需任何的参数,然后返回被包装在其中的表达式的值。这种语法糖(syntactic convenience),让你能够用一个普通的表达式,省略围绕在函数参数外的括号,来代替显式的闭包。
|
||||||
|
调用一个闭包作为参数的函数是很常见的,不过,实现那样的函数却不常见。举个例子来说,`assert(condition:message:file:line:)`函数,将一个闭包作为它的condition参数和message参数;它的condition参数仅仅在编译时被计算求值,它的message参数仅当Condition参数为false时被计算求值。
|
||||||
|
一个自动闭包让你能够延迟计算求值,因为代码段不会被执行直到你调用这个闭包。延迟计算求值对于哪些有副作用(Side Effect)的代码和大量繁杂计算的代码来说是很有益处的,因为它让你控制了代码什么时候被运行。下面的代码展示了一个闭包的延时执行。
|
||||||
|
|
||||||
|
```swift
|
||||||
|
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
|
||||||
|
print(customersInLine.count)
|
||||||
|
// prints "5"
|
||||||
|
|
||||||
|
let customerProvider = { customersInLine.removeAtIndex(0) }
|
||||||
|
print(customersInLine.count)
|
||||||
|
// prints "5"
|
||||||
|
|
||||||
|
print("Now serving \(customerProvider())!")
|
||||||
|
// prints "Now serving Chris!"
|
||||||
|
print(customersInLine.count)
|
||||||
|
// prints "4"
|
||||||
|
```
|
||||||
|
|
||||||
|
尽管在闭包的代码中,`customersInLine`的第一个元素被移除了,不过在闭包被调用之前,这个元素是不会被真正移除的。如果这个闭包永远不被调用,那么在闭包里面的表达式将永远不会之行,那意味着列表中的元素永远不会被移除。请注意,`customerProvider`的类型不是一个字符(String),而是一个`() -> String`,一个没有参数而返回值为字符(String)的函数。
|
||||||
|
|
||||||
|
你当你将一个闭包作为参数传递到函数中,你能够看到相同的延时计算的行为。
|
||||||
|
|
||||||
|
```swift
|
||||||
|
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
|
||||||
|
func serveCustomer(customerProvider: () -> String) {
|
||||||
|
print("Now serving \(customerProvider())!")
|
||||||
|
}
|
||||||
|
serveCustomer( { customersInLine.removeAtIndex(0) } )
|
||||||
|
// prints "Now serving Alex!"
|
||||||
|
```
|
||||||
|
|
||||||
|
`serveCustomer(_:) ` 需要一个显式的闭包用来返回一个顾客的名字。下面这个版本的`serveCustomer(_:)`完成了相同的操作,不过他通过将一个参数标记为`@autoclosure`特性,来代替一个显式的闭包作为参数。现在你可以使用一个‘以字符为参数的函数’作为参数,而不是用一个‘闭包’作为参数来调用这个函数了。这个被调用的函数参数将自动转化为一个闭包参数,因为`customerProvider`被打上了`@autoclosure`特性标志。
|
||||||
|
|
||||||
|
```swift
|
||||||
|
// customersInLine is ["Ewa", "Barry", "Daniella"]
|
||||||
|
func serveCustomer(@autoclosure customerProvider: () -> String) {
|
||||||
|
print("Now serving \(customerProvider())!")
|
||||||
|
}
|
||||||
|
serveCustomer(customersInLine.removeAtIndex(0))
|
||||||
|
// prints "Now serving Ewa!"
|
||||||
|
```
|
||||||
|
|
||||||
|
> 注意:
|
||||||
|
> 过度使用 `autoclosures` 会让你的代码变得难以理解,上下文和函数名应该能够明确的表示出,他是被延迟执行的。
|
||||||
|
|
||||||
|
`@autoclosure` 特性隐式包括了 `@noescape` 特性, 它意味着闭包仅仅在函数中被使用,这个闭包不允许以被保存起来的方式,让它’逃逸‘出当前的作用域,然后在函数返回之后再被执行,如果你想让这个闭包可以‘逃逸’,则应该使用 `@autoclosure(escaping)`特性.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
// customersInLine is ["Barry", "Daniella"]
|
||||||
|
var customerProviders: [() -> String] = []
|
||||||
|
func collectCustomerProviders(@autoclosure(escaping) customerProvider: () -> String) {
|
||||||
|
customerProviders.append(customerProvider)
|
||||||
|
}
|
||||||
|
collectCustomerProviders(customersInLine.removeAtIndex(0))
|
||||||
|
collectCustomerProviders(customersInLine.removeAtIndex(0))
|
||||||
|
|
||||||
|
print("Collected \(customerProviders.count) closures.")
|
||||||
|
// prints "Collected 2 closures."
|
||||||
|
for customerProvider in customerProviders {
|
||||||
|
print("Now serving \(customerProvider())!")
|
||||||
|
}
|
||||||
|
// prints "Now serving Barry!"
|
||||||
|
// prints "Now serving Daniella!"
|
||||||
|
```
|
||||||
|
|
||||||
|
在上面的代码中,代替调用传入的customer参数闭包,`collectCustomerProviders(_:) `函数将闭包追加到了`customerProviders`队列中,这个队列定义在函数作用域范围外,那就意味着,在队列里面的闭包将会在函数返回之后被执行。作为结果,customer参数的值必须允许‘逃逸’出函数作用域。
|
||||||
|
|
||||||
|
更多关于 `@autoclosure` 和 `@noescape` 特性的信息, 参见 Declaration Attributes.
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
- [字面量(*Literals*)](#literals)
|
- [字面量(*Literals*)](#literals)
|
||||||
- [运算符(*Operators*)](#operators)
|
- [运算符(*Operators*)](#operators)
|
||||||
|
|
||||||
Swift 的“词法结构(*lexical structure*)”描述了能构成该语言中合法标记(*tokens*)的字符序列。这些合法标记组成了语言中最底层的构建基块,并在之后的章节中用于描述语言的其他部分。
|
Swift 的“词法结构(*lexical structure*)”描述了能构成该语言中合法标记(*tokens*)的字符序列。这些合法标记组成了语言中最底层的构建基块,并在之后的章节中用于描述语言的其他部分。一个合法标记由一个标识符、关键字、标点符号、文字或运算符组成。
|
||||||
|
|
||||||
通常情况下,标记是在随后将介绍的语法约束下,由 Swift 源文件的输入文本中提取可能的最长子串生成。这种方法称为“最长匹配项(*longest match*)”,或者“最大适合”(*maximal munch*)。
|
通常情况下,标记是在随后将介绍的语法约束下,由 Swift 源文件的输入文本中提取可能的最长子串生成。这种方法称为“最长匹配项(*longest match*)”,或者“最大适合”(*maximal munch*)。
|
||||||
|
|
||||||
@ -28,6 +28,8 @@ Swift 的“词法结构(*lexical structure*)”描述了能构成该语言
|
|||||||
|
|
||||||
注释(*comments*)被编译器当作空白处理。单行注释由 `//` 开始直至遇到换行符(*line feed*)(U+000A)或者回车符(*carriage return*)(U+000D)。多行注释由 `/*` 开始,以 `*/` 结束。注释允许嵌套,但注释标记必须匹配。
|
注释(*comments*)被编译器当作空白处理。单行注释由 `//` 开始直至遇到换行符(*line feed*)(U+000A)或者回车符(*carriage return*)(U+000D)。多行注释由 `/*` 开始,以 `*/` 结束。注释允许嵌套,但注释标记必须匹配。
|
||||||
|
|
||||||
|
就像 [标记格式引用(Markup Formatting Reference)](https://developer.apple.com/library/prerelease/ios/documentation/Xcode/Reference/xcode_markup_formatting_ref/index.html#//apple_ref/doc/uid/TP40016497) 所说的那样,注释可以包含附加的格式和标记。
|
||||||
|
|
||||||
<a id="identifiers"></a>
|
<a id="identifiers"></a>
|
||||||
## 标识符
|
## 标识符
|
||||||
|
|
||||||
@ -207,7 +209,14 @@ true // 布尔型字面量
|
|||||||
let x = 3; "1 2 \(x)"
|
let x = 3; "1 2 \(x)"
|
||||||
```
|
```
|
||||||
|
|
||||||
字符串字面量的默认推导类型为 `String`。组成字符串的字符默认推导类型为 `Character`。更多有关 `String` 和 `Character` 的信息请参照 [字符串和字符](../chapter2/03_Strings_and_Characters.html)。
|
字符串字面量的默认推导类型为 `String`。组成字符串的字符默认推导类型为 `Character`。更多有关 `String` 和 `Character` 的信息请参照 [字符串和字符](../chapter2/03_Strings_and_Characters.html) 以及[字符串结构参考](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_String_Structure/index.html#//apple_ref/doc/uid/TP40015181)。
|
||||||
|
|
||||||
|
用 `+` 操作符连接的字符型字面量是在编译时进行连接的。比如下面的 `textA` 和 `textB` 时完全一样的—— `textA` 没有任何运行时的连接操作。
|
||||||
|
|
||||||
|
```
|
||||||
|
let textA = "Hello " + "world"
|
||||||
|
let textB = "Hello world"
|
||||||
|
```
|
||||||
|
|
||||||
> 字符型字面量语法
|
> 字符型字面量语法
|
||||||
> *字符串字面量* → **"** [*引用文本*](#quoted_text)<sub>可选</sub> **"**
|
> *字符串字面量* → **"** [*引用文本*](#quoted_text)<sub>可选</sub> **"**
|
||||||
|
|||||||
@ -98,25 +98,15 @@ var someValue: ExampleModule.MyType
|
|||||||
|
|
||||||
由于 *参数类型* 和 *返回值类型* 可以是元组类型,所以函数类型支持多参数与多返回值的函数与方法。。
|
由于 *参数类型* 和 *返回值类型* 可以是元组类型,所以函数类型支持多参数与多返回值的函数与方法。。
|
||||||
|
|
||||||
对于参数类型是空元组类型`()`以及返回值类型为表达式类型的函数类型,你可以对其参数声明使用`autoclosure`(见声明属性章节)。一个自动闭包函数捕获特定表达式上的隐式闭包而非表达式本身。下面的例子使用`autoclosure`属性来定义一个很简单的assert函数:
|
对于参数类型是空元组类型`()`以及返回值类型为表达式类型的函数类型,你可以对其参数声明使用`autoclosure`(见声明属性章节)。一个自动闭包函数捕获特定表达式上的隐式闭包而非表达式本身。这从语法结构上提供了一种便捷:延迟对表达式的求值,直到在函数体中有使用它的值。以自动闭包函数类型做为参数的例子详见 [自动闭包(Autoclosures)](TODO:添加链接) 。
|
||||||
|
|
||||||
```swift
|
函数类型可以拥有一个可变长参数作为参数类型中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字紧随三个点`(...)`组成,如`Int...`。可变长参数被认为是一个包含了基础类型元素的数组。即`Int...`就是`[Int]`。关于使用可变长参数的例子,见章节[Variadic Parameters](TODO:添加链接)。
|
||||||
func simpleAssert(@autoclosure condition: Void -> Bool, _ message: String) {
|
|
||||||
if !condition() {
|
|
||||||
print(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let testNumber = 5
|
|
||||||
simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.")
|
|
||||||
// prints "testNumber isn't an even number."
|
|
||||||
```
|
|
||||||
函数类型可以拥有一个可变长参数作为参数类型中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字紧随三个点`(...)`组成,如`Int...`。可变长参数被认为是一个包含了基础类型元素的数组。即`Int...`就是`[Int]`。关于使用可变长参数的例子,见章节Variadic Parameters。
|
|
||||||
|
|
||||||
为了指定一个`in-out`参数,可以在参数类型前加`inout`前缀。但是你不可以对可变长参数或返回值类型使用`inout`。关于In-Out参数的讨论见章节In-Out参数部分。
|
为了指定一个`in-out`参数,可以在参数类型前加`inout`前缀。但是你不可以对可变长参数或返回值类型使用`inout`。关于In-Out参数的讨论见章节[In-Out参数部分](TODO:添加链接)。
|
||||||
|
|
||||||
柯里化函数(Curried fuction)的函数类型从右向左递归地组成一组。例如,函数类型`Int -> Int -> Int`可以被理解为`Int -> (Int -> Int)`——也就是说,一个函数的参数为`Int`类型,其返回类型是一个参数类型为`Int`返回类型为`Int`的函数类型。关于柯里化函数的讨论见章节Curried Fuctions。
|
柯里化函数(Curried fuction)的函数类型从右向左递归地组成一组。例如,函数类型`Int -> Int -> Int`可以被理解为`Int -> (Int -> Int)`——也就是说,一个函数的参数为`Int`类型,其返回类型是一个参数类型为`Int`返回类型为`Int`的函数类型。关于柯里化函数的讨论见章节[Curried Fuctions](TODO:添加链接)。
|
||||||
|
|
||||||
函数类型若要抛出错误就必须使用`throws`关键字来标记,若要重抛错误则必须使用`rethrows`关键字来标记。`throws`关键字是函数类型的一部分,不抛出函数(nonthrowing function)是抛出函数(throwing function)函数的一个子类型。因此,在使用抛出函数的地方也可以使用不抛出函数。对于柯里化函数,`throws`关键字只应用于最里层的函数。抛出和重抛函数(rethrowing function)的相关描述见章节抛出函数与方法和重抛函数与方法。
|
函数类型若要抛出错误就必须使用`throws`关键字来标记,若要重抛错误则必须使用`rethrows`关键字来标记。`throws`关键字是函数类型的一部分,不抛出函数(nonthrowing function)是抛出函数(throwing function)函数的一个子类型。因此,在使用抛出函数的地方也可以使用不抛出函数。对于柯里化函数,`throws`关键字只应用于最里层的函数。抛出和重抛函数(rethrowing function)的相关描述见章节[抛出函数与方法](TODO:添加链接)和[重抛函数与方法](TODO:添加链接)。
|
||||||
|
|
||||||
> 函数类型语法
|
> 函数类型语法
|
||||||
> *函数类型* → [*类型*](../chapter3/03_Types.html#type) _抛出_ _可选_ **->** [*类型*](../chapter3/03_Types.html#type)
|
> *函数类型* → [*类型*](../chapter3/03_Types.html#type) _抛出_ _可选_ **->** [*类型*](../chapter3/03_Types.html#type)
|
||||||
@ -141,7 +131,7 @@ var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
|||||||
```
|
```
|
||||||
访问一个多维数组的元素时,最左边的下标指向最外层数组的相应位置元素。接下来往右的下标指向第一层嵌入的相应位置元素,依次类推。这就意味着,在上面的例子中,`array3D[0]`是指`[[1, 2], [3, 4]]`,`array3D[0][1]`是指`[3, 4]`,`array3D[0][1][1]`则是指值`4`。
|
访问一个多维数组的元素时,最左边的下标指向最外层数组的相应位置元素。接下来往右的下标指向第一层嵌入的相应位置元素,依次类推。这就意味着,在上面的例子中,`array3D[0]`是指`[[1, 2], [3, 4]]`,`array3D[0][1]`是指`[3, 4]`,`array3D[0][1][1]`则是指值`4`。
|
||||||
|
|
||||||
关于Swift标准库中`Array`类型的细节讨论,见章节Arrays。
|
关于Swift标准库中`Array`类型的细节讨论,见章节[Arrays](TODO:添加链接)。
|
||||||
|
|
||||||
> 数组类型语法
|
> 数组类型语法
|
||||||
> *数组类型* → [*类型*](../chapter3/03_Types.html#type)
|
> *数组类型* → [*类型*](../chapter3/03_Types.html#type)
|
||||||
@ -162,7 +152,7 @@ let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]
|
|||||||
|
|
||||||
字典中键的类型必须遵循Swift标准库中的可哈希协议。
|
字典中键的类型必须遵循Swift标准库中的可哈希协议。
|
||||||
|
|
||||||
关于Swift标准库中`Dictionary`类型的更多细节可查看章节Dictionaries。
|
关于Swift标准库中`Dictionary`类型的更多细节可查看章节[Dictionaries](TODO:添加链接)。
|
||||||
|
|
||||||
> 字典类型语法
|
> 字典类型语法
|
||||||
> *字典类型* → **[**[*类型*](../chapter3/03_Types.html#type) **:** [*类型*](../chapter3/03_Types.html#type) **]**
|
> *字典类型* → **[**[*类型*](../chapter3/03_Types.html#type) **:** [*类型*](../chapter3/03_Types.html#type) **]**
|
||||||
@ -192,7 +182,7 @@ optionalInteger! // 42
|
|||||||
|
|
||||||
你也可以使用可选链和可选绑定来选择性的执行可选表达式上的操作。如果值为`nil`,不会执行任何操作因此也就没有运行错误产生。
|
你也可以使用可选链和可选绑定来选择性的执行可选表达式上的操作。如果值为`nil`,不会执行任何操作因此也就没有运行错误产生。
|
||||||
|
|
||||||
更多细节以及更多如何使用可选类型的例子,见章节Optionals。
|
更多细节以及更多如何使用可选类型的例子,见章节[Optionals](TODO:添加链接)。
|
||||||
|
|
||||||
> 可选类型语法
|
> 可选类型语法
|
||||||
> *可选类型* → [*类型*](../chapter3/03_Types.html#type) **?**
|
> *可选类型* → [*类型*](../chapter3/03_Types.html#type) **?**
|
||||||
@ -216,7 +206,7 @@ var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional<String>
|
|||||||
|
|
||||||
使用可选链会选择性的执行隐式解析可选表达式上的某一个操作。如果值为`nil`,就不会执行任何操作,因此也不会产生运行错误。
|
使用可选链会选择性的执行隐式解析可选表达式上的某一个操作。如果值为`nil`,就不会执行任何操作,因此也不会产生运行错误。
|
||||||
|
|
||||||
关于隐式解析可选的更多细节,见章节Implicitly Unwrapped Optionals。
|
关于隐式解析可选的更多细节,见章节[Implicitly Unwrapped Optionals](TODO:添加链接)。
|
||||||
|
|
||||||
> 隐式解析可选类型(Implicitly Unwrapped Optional Type)语法
|
> 隐式解析可选类型(Implicitly Unwrapped Optional Type)语法
|
||||||
> *隐式解析可选类型* → [*类型*](../chapter3/03_Types.html#type) **!**
|
> *隐式解析可选类型* → [*类型*](../chapter3/03_Types.html#type) **!**
|
||||||
@ -267,9 +257,33 @@ let someInstance: SomeBaseClass = SomeSubClass()
|
|||||||
someInstance.dynamicType.printClassName()
|
someInstance.dynamicType.printClassName()
|
||||||
// prints "SomeSubClass
|
// prints "SomeSubClass
|
||||||
```
|
```
|
||||||
> 注意
|
|
||||||
> **不能创建元类型类的实例,因为不能保证其子类会提供初始化的代码。**
|
|
||||||
|
|
||||||
|
可以使用恒等运算符(`===`和 `!==`)来测试一个实例的运行时类型和它的编译时类型是否一致。
|
||||||
|
|
||||||
|
```
|
||||||
|
if someInstance.dynamicType === someInstance.self {
|
||||||
|
print("The dynamic type of someInstance is SomeBaseCass")
|
||||||
|
} else {
|
||||||
|
print("The dynamic type of someInstance isn't SomeBaseClass")
|
||||||
|
}
|
||||||
|
// prints "The dynamic type of someInstance isn't SomeBaseClass"
|
||||||
|
```
|
||||||
|
|
||||||
|
可以使用初始化表达式从某个类型的元类型构造出一个该类型的实例。对于类实例,必须使用 `required` 关键字标记被调用的构造器,或者使用 `final` 关键字标记整个类。
|
||||||
|
|
||||||
|
```
|
||||||
|
class AnotherSubClass: SomeBaseClass {
|
||||||
|
let string: String
|
||||||
|
required init(string: String) {
|
||||||
|
self.string = string
|
||||||
|
}
|
||||||
|
override class func printClassName() {
|
||||||
|
print("AnotherSubClass")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let metatype: AnotherSubClass.Type = AnotherSubClass.self
|
||||||
|
let anotherInstance = metatype.init(string: "some string")
|
||||||
|
```
|
||||||
|
|
||||||
> 元(Metatype)类型语法
|
> 元(Metatype)类型语法
|
||||||
> *元类型* → [*类型*](../chapter3/03_Types.html#type) **.** **Type** | [*类型*](../chapter3/03_Types.html#type) **.** **Protocol**
|
> *元类型* → [*类型*](../chapter3/03_Types.html#type) **.** **Type** | [*类型*](../chapter3/03_Types.html#type) **.** **Protocol**
|
||||||
|
|||||||
@ -31,9 +31,11 @@ Swift 中存在四种表达式: 前缀(prefix)表达式,二元(binary
|
|||||||
|
|
||||||
前缀表达式由可选的前缀符号和表达式组成。(这个前缀符号只能接收一个参数)
|
前缀表达式由可选的前缀符号和表达式组成。(这个前缀符号只能接收一个参数)
|
||||||
|
|
||||||
对于这些操作符的使用,请参见: Basic Operators and Advanced Operators
|
对于这些操作符的使用,请参见: [Basic Operators](TODO:添加链接) 和 [Advanced Operators](TODO:添加链接)
|
||||||
|
|
||||||
作为对上面标准库运算符的补充,你也可以对 某个函数的参数使用 '&'运算符。 更多信息,请参见: "In-Out parameters".
|
对于 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)。
|
||||||
|
|
||||||
|
作为对上面标准库运算符的补充,你也可以对 某个函数的参数使用 '&'运算符。 更多信息,请参见: [In-Out parameters](TODO:添加链接).
|
||||||
|
|
||||||
> 前置表达式语法
|
> 前置表达式语法
|
||||||
> *前置表达式* → [*前置运算符*](LexicalStructure.html#prefix_operator) _可选_ [*后置表达式*](../chapter3/04_Expressions.html#postfix_expression)
|
> *前置表达式* → [*前置运算符*](LexicalStructure.html#prefix_operator) _可选_ [*后置表达式*](../chapter3/04_Expressions.html#postfix_expression)
|
||||||
@ -46,9 +48,21 @@ try表达式由紧跟在可能会出错的表达式后面的`try`操作符组成
|
|||||||
`try expression`
|
`try expression`
|
||||||
强制的try表示由紧跟在可能会出错的表达式后面的`try!`操作符组成,出错时会产生一个运行时错误,形式如下:
|
强制的try表示由紧跟在可能会出错的表达式后面的`try!`操作符组成,出错时会产生一个运行时错误,形式如下:
|
||||||
`try! expression`
|
`try! expression`
|
||||||
关于`try`更多的例子和信息请参见:Catching and Handling Errors.
|
|
||||||
|
当在二进制运算符左边的表达式被标记上 `try`、`try?` 或者 `try!` 时,这个操作对整个二进制表达式都产生作用。也就是说,你可以使用圆括号来明确操作符的应用范围。
|
||||||
|
|
||||||
|
```
|
||||||
|
sum = try someThrowingFunction() + anotherThrowingFunction() // try 对两个方法调用都产生作用
|
||||||
|
sum = try (someThrowingFunction() + anotherThrowingFunction()) // try 对两个方法调用都产生作用
|
||||||
|
sum = (try someThrowingFunction()) + anotherThrowingFunction() // Error: try 只对第一个方法调用产生作用
|
||||||
|
```
|
||||||
|
|
||||||
|
`try` 表达式不能出现在二进制操作符的的右边,除非二进制操作符是赋值操作符或者 `try` 表达式是被圆括号括起来的。
|
||||||
|
|
||||||
|
关于`try`、`try?` 和 `try!` 更多的例子和信息请参见:[Error Handling](TODO:添加链接)
|
||||||
|
|
||||||
> try表达式语法
|
> try表达式语法
|
||||||
> *try 操作符* → [*try*](LexicalStructure.html#try_operator) | *try!*
|
> *try 操作符* → [*try*](LexicalStructure.html#try_operator) | try? | *try!*
|
||||||
|
|
||||||
<a name="binary_expressions"></a>
|
<a name="binary_expressions"></a>
|
||||||
## 二元表达式(Binary Expressions)
|
## 二元表达式(Binary Expressions)
|
||||||
@ -57,7 +71,7 @@ try表达式由紧跟在可能会出错的表达式后面的`try`操作符组成
|
|||||||
|
|
||||||
> `left-hand argument` `operator` `right-hand argument`
|
> `left-hand argument` `operator` `right-hand argument`
|
||||||
|
|
||||||
关于这些运算符(operators)的更多信息,请参见:Basic Operators and Advanced Operators.
|
关于这些运算符(operators)的更多信息,请参见:[Basic Operators](TODO:添加链接)和 [Advanced Operators](TODO:添加链接)。
|
||||||
|
|
||||||
> 注意
|
> 注意
|
||||||
> 在解析时, 一个二元表达式表示为一个一级数组(a flat list), 这个数组(List)根据运算符的先后顺序,被转换成了一个tree. 例如: 2 + 3 * 5 首先被认为是: 2, + , `` 3``, *, 5. 随后它被转换成 tree (2 + (3 * 5))
|
> 在解析时, 一个二元表达式表示为一个一级数组(a flat list), 这个数组(List)根据运算符的先后顺序,被转换成了一个tree. 例如: 2 + 3 * 5 首先被认为是: 2, + , `` 3``, *, 5. 随后它被转换成 tree (2 + (3 * 5))
|
||||||
@ -137,7 +151,7 @@ f(x as Any)
|
|||||||
|
|
||||||
`a!`操作符表示强制转换,其返回指定的类型,而不是可选的类型。如果转换失败,则会出现运行时错误。表达式`x as T` 效果等同于`(x as? T)!`。
|
`a!`操作符表示强制转换,其返回指定的类型,而不是可选的类型。如果转换失败,则会出现运行时错误。表达式`x as T` 效果等同于`(x as? T)!`。
|
||||||
|
|
||||||
关于类型转换的更多内容和例子,请参见: Type Casting.
|
关于类型转换的更多内容和例子,请参见: [Type Casting](TODO:添加链接).
|
||||||
|
|
||||||
> 类型转换运算符(type-casting-operator)语法
|
> 类型转换运算符(type-casting-operator)语法
|
||||||
> *类型转换运算符* → **is** [*类型*](../chapter3/03_Types.html#type)
|
> *类型转换运算符* → **is** [*类型*](../chapter3/03_Types.html#type)
|
||||||
@ -283,7 +297,7 @@ struct Point {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
闭包的参数声明形式跟方法中的声明一样, 请参见:Function Declaration.
|
闭包的参数声明形式跟方法中的声明一样, 请参见:[Function Declaration](TODO:添加链接).
|
||||||
|
|
||||||
闭包还有几种特殊的形式, 让使用更加简洁:
|
闭包还有几种特殊的形式, 让使用更加简洁:
|
||||||
|
|
||||||
@ -309,9 +323,11 @@ myFunction { return $0 + $1 }
|
|||||||
myFunction { $0 + $1 }
|
myFunction { $0 + $1 }
|
||||||
```
|
```
|
||||||
|
|
||||||
关于 向闭包中传递参数的内容,参见: Function Call Expression.
|
关于 向闭包中传递参数的内容,参见: [Function Call Expression](TODO:添加链接).
|
||||||
|
|
||||||
闭包表达式可以通过一个参数列表(capture list) 来显式指定它需要的参数。 参数列表 由中括号 [] 括起来,里面的参数由逗号','分隔。一旦使用了参数列表,就必须使用'in'关键字(在任何情况下都得这样做,包括忽略参数的名字,type, 返回值时等等)。
|
### 参数列表(Capture Lists)
|
||||||
|
|
||||||
|
闭包表达式可以通过一个参数列表(capture list) 来显式指定它需要的参数。 参数列表由中括号 [] 括起来,里面的参数由逗号','分隔。一旦使用了参数列表,就必须使用'in'关键字(在任何情况下都得这样做,包括忽略参数的名字,type, 返回值时等等)。
|
||||||
|
|
||||||
在闭包的参数列表( capture list)中, 参数可以声明为 'weak' 或者 'unowned' .
|
在闭包的参数列表( capture list)中, 参数可以声明为 'weak' 或者 'unowned' .
|
||||||
|
|
||||||
@ -328,7 +344,7 @@ myFunction { [unowned self] in print(self.title) } // unowned capture
|
|||||||
myFunction { [weak parent = self.parent] in print(parent!.title) }
|
myFunction { [weak parent = self.parent] in print(parent!.title) }
|
||||||
```
|
```
|
||||||
|
|
||||||
关于闭包表达式的更多信息和例子,请参见: Closure Expressions.
|
关于闭包表达式的更多信息和例子,请参见: [Closure Expressions](TODO:添加链接),关于更多参数列表的信息和例子,请参见: [Resolving Strong Reference Cycles for Closures](TODO:添加链接)。
|
||||||
|
|
||||||
> 闭包表达式语法
|
> 闭包表达式语法
|
||||||
> *闭包表达式* → **{** [*闭包签名(Signational)*](../chapter3/04_Expressions.html#closure_signature) _可选_ [*多条语句(Statements)*](../chapter3/10_Statements.html#statements) **}**
|
> *闭包表达式* → **{** [*闭包签名(Signational)*](../chapter3/04_Expressions.html#closure_signature) _可选_ [*多条语句(Statements)*](../chapter3/10_Statements.html#statements) **}**
|
||||||
|
|||||||
@ -16,9 +16,9 @@
|
|||||||
- [带标签的语句](#labeled_statement)
|
- [带标签的语句](#labeled_statement)
|
||||||
- [控制传递语句](#control_transfer_statements)
|
- [控制传递语句](#control_transfer_statements)
|
||||||
|
|
||||||
在 Swift 中,有两种类型的语句:简单语句和控制流语句。简单语句是最常见的,用于构造表达式或者声明。控制流语句则用于控制程序执行的流程,Swift 中有三种类型的控制流语句:循环语句、分支语句和控制传递语句。
|
在 Swift 中,有三种类型的语句:简单语句、编译控制语句和控制流语句。简单语句是最常见的,用于构造表达式或者声明。编译控制语句允许程序改变编译器的行为以及包含构建配置和源代码控制语句。
|
||||||
|
|
||||||
循环语句用于重复执行代码块;分支语句用于执行满足特定条件的代码块;控制传递语句则用于修改代码的执行顺序。在稍后的叙述中,将会详细地介绍每一种类型的控制流语句。
|
控制流语句则用于控制程序执行的流程,Swift 中有几种类型的控制流语句:循环语句、分支语句和控制传递语句。循环语句用于重复执行代码块;分支语句用于执行满足特定条件的代码块;控制传递语句则用于修改代码的执行顺序。另外,Swift 提供了 `do` 语句来引入范围以及捕获和处理错误,还提供了 `defer` 语句在退出当前范围之前执行清理操作。
|
||||||
|
|
||||||
是否将分号(`;`)添加到语句的结尾处是可选的。但若要在同一行内写多条独立语句,请务必使用分号。
|
是否将分号(`;`)添加到语句的结尾处是可选的。但若要在同一行内写多条独立语句,请务必使用分号。
|
||||||
|
|
||||||
@ -467,11 +467,8 @@ swift 中的 do 语句与C 中限定代码块界限的大括号 ({})很相
|
|||||||
`statements`
|
`statements`
|
||||||
> }
|
> }
|
||||||
|
|
||||||
|
|
||||||
如同`switch`语句,编译器会判断`catch`子句是否被遗漏。如果catch没有被遗漏,则认为错误被处理。否则,错误会自动传播出包含作用域,被一个封闭的`catch`语句或抛出函数处理掉,包含函数必须以`throws`关键字声明。
|
如同`switch`语句,编译器会判断`catch`子句是否被遗漏。如果catch没有被遗漏,则认为错误被处理。否则,错误会自动传播出包含作用域,被一个封闭的`catch`语句或抛出函数处理掉,包含函数必须以`throws`关键字声明。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
为了确保错误已经被处理,使用一个匹配所有错误的`catch`子句,如通配符模式(_)。如果一个`catch`子句不指定一种模式,`catch`子句会匹配和约束任何局部变量命名的`error`。有关在`catch`子句中使用模式的更多信息,详见[模式](TODO)。
|
为了确保错误已经被处理,使用一个匹配所有错误的`catch`子句,如通配符模式(_)。如果一个`catch`子句不指定一种模式,`catch`子句会匹配和约束任何局部变量命名的`error`。有关在`catch`子句中使用模式的更多信息,详见[模式](TODO)。
|
||||||
|
|
||||||
关于在一些`catch`子句中如何使用` do`语句的例子,详情参见[错误处理](TODO)一章的[抛出错误](TODO)。
|
关于在一些`catch`子句中如何使用` do`语句的例子,详情参见[错误处理](TODO)一章的[抛出错误](TODO)。
|
||||||
@ -480,6 +477,101 @@ swift 中的 do 语句与C 中限定代码块界限的大括号 ({})很相
|
|||||||
> catch → *[catch子句](TODO) [catch子句](TODO)*
|
> catch → *[catch子句](TODO) [catch子句](TODO)*
|
||||||
> catch → **catch** *[*模式*](../chapter3/07_Patterns.html#pattern)** *可选的* [*where*]() *可选的* [*代码块*](../chapter3/05_Declarations.html#code_block)
|
> catch → **catch** *[*模式*](../chapter3/07_Patterns.html#pattern)** *可选的* [*where*]() *可选的* [*代码块*](../chapter3/05_Declarations.html#code_block)
|
||||||
|
|
||||||
|
<a name="compiler_control_statements"></a>
|
||||||
|
### 编译控制语句
|
||||||
|
|
||||||
|
编译控制语句允许程序改变编译器的行为。Swift 有两种编译控制语句:构建配置语句和源代码控制语句。
|
||||||
|
|
||||||
|
> 编译控制语句语法
|
||||||
|
> *编译控制语句* → [*构建配置语句*](../chapter3/04_Expressions.html#build_config_statements)
|
||||||
|
> *编译控制语句* → [*源代码控制语句*](../chapter3/04_Expressions.html#line_control_statements)
|
||||||
|
|
||||||
|
<a name="build_config_statements"></a>
|
||||||
|
#### 构建配置语句
|
||||||
|
|
||||||
|
构建配置语句可以根据一个或多个配置项来有条件的编译代码。
|
||||||
|
|
||||||
|
每一个构建配置语句都以 `#if` 开始, `#endif` 结束。如下是一个简单的构建配置语句:
|
||||||
|
|
||||||
|
```
|
||||||
|
#if build configuration
|
||||||
|
statements
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
和 `if` 语句的条件不同,构建配置的条件是在编译时进行判断的。它的结果是:只有构建配置在编译时判断为 `true` 的情况下语句才会被编译和执行。
|
||||||
|
|
||||||
|
*构建配置* 可以是 `true` 和 `false` 的常量,也可以是使用 `-D` 命令行标志的标识符,或者是下列表格中的任意一个平台测试方法。
|
||||||
|
|
||||||
|
| 方法 | 可用参数 |
|
||||||
|
| --- | - |
|
||||||
|
| os() | OSX, iOS, watchOS, tvOS |
|
||||||
|
| arch() | i386, x86_64, arm, arm64 |
|
||||||
|
|
||||||
|
|
||||||
|
> 注意
|
||||||
|
> `arch(arm)` 构建配置在 ARM 64位设备上不会返回 `true`。如果代码的构建目标是 32 位的 iOS 模拟器,`arch(i386)` 构建配置返回 `true`。
|
||||||
|
|
||||||
|
你可以使用逻辑操作符 `&&`、`||` 和 `!` 来连接构建配置,还可以使用圆括号来进行分组。
|
||||||
|
|
||||||
|
就像 `if` 语句一样,你可以使用 `#elseif` 分句来添加任意多个条件分支来测试不同的构建配置。你也可以使用 `#else` 分句来添加最终的条件分支。包含多个分支的构建配置语句例子如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
#if build configuration 1
|
||||||
|
statements to compile if build configuration 1 is true
|
||||||
|
#elseif build configuration 2
|
||||||
|
statements to compile if build configuration 2 is true
|
||||||
|
#else
|
||||||
|
statements to compile if both build configurations are false
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
> 注意
|
||||||
|
> 即使没有被编译,构建配置语句中的每一个分句仍然会被解析。
|
||||||
|
|
||||||
|
---
|
||||||
|
> 构建配置语句语法
|
||||||
|
> 单个构建配置语句 → #if 多个构建配置语句(可选) 多个构建配置 `elseif` 分句(可选) 单个构建配置 `else` 分句(可选)#endif
|
||||||
|
> 多个构建配置 `elseif` 分句 → 单个构建配置 `elseif` 分句 多个构建配置 `elseif` 分句(可选)
|
||||||
|
> 单个构建配置 `elseif` 分句 → #elseif 多个构建配置语句(可选)
|
||||||
|
> 单个构建配置 `else` 分句 → #else 语句(可选)
|
||||||
|
> 构建配置 → 平台测试方法
|
||||||
|
> 构建配置 → 标识符
|
||||||
|
> 构建配置 → boolean 常量
|
||||||
|
> 构建配置 → (构建配置)
|
||||||
|
> 构建配置 → ! 构建配置
|
||||||
|
> 构建配置 → 构建配置 && 构建配置
|
||||||
|
> 构建配置 → 构建配置 || 构建配置
|
||||||
|
> 平台测试方法 → os(操作系统)
|
||||||
|
> 平台测试方法 → arch(架构)
|
||||||
|
> 操作系统 → OSX iOS watchOS tvOS
|
||||||
|
> 架构 → i386 x86_64 arm arm64
|
||||||
|
|
||||||
|
<a name="line_control_statements"></a>
|
||||||
|
#### 源代码控制语句
|
||||||
|
|
||||||
|
源代码控制语句用来给被编译源代码指定一个与原始行号和文件名不同的行号和文件名。使用源代码控制语句可以改变 Swift 使用源代码的位置,以便进行分析和测试。
|
||||||
|
|
||||||
|
源代码的控制语句的例子如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
#line line number filename
|
||||||
|
```
|
||||||
|
|
||||||
|
源代码控制语句改变了常量表达式 `__LINE__` 和 `__FILE__` 的值,以一行源代码开头,然后跟着源代码控制语句。`line number` 改变了 `__LINE__` 的值,它是一个大于 0 的常量。`filename` 改变了 `__FILE__` 的值,它是一个字符串常量。
|
||||||
|
|
||||||
|
你可以通过写一句不指定 `line number` 和 `filename` 的源代码控制语句来吧源代码的位置回退到初始的行号和文件。
|
||||||
|
|
||||||
|
源代码控制语句必须出现在源代码的那一行,而且不能是源代码文件的最后一行。
|
||||||
|
|
||||||
|
> 源代码控制语句
|
||||||
|
|
||||||
|
> 源代码控制语句 → #line
|
||||||
|
> 源代码控制语句 → #line line-number file-name
|
||||||
|
> line-number → 大于 0 的十进制数
|
||||||
|
> file-name → 字符串常量
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user