# 語句(Statements){#statement-statements}
在 Swift 中,有三種類型的語句:簡單語句、編譯器控制語句和控制流語句。簡單語句是最常見的,用于構造表達式或者聲明。編譯器控制語句允許程序改變編譯器的行為,包含編譯配置語句和行控制語句。
控制流語句則用于控制程序執行的流程,Swift 中有多種類型的控制流語句:循環語句、分支語句和控制轉移語句。循環語句用于重復執行代碼塊;分支語句用于執行滿足特定條件的代碼塊;控制轉移語句則用于改變代碼的執行順序。另外,Swift 提供了 `do` 語句,用于構建局部作用域,還用于錯誤的捕獲和處理;還提供了 `defer` 語句,用于退出當前作用域之前執行清理操作。
是否將分號(`;`)添加到語句的末尾是可選的。但若要在同一行內寫多條獨立語句,則必須使用分號。
> 語句語法
>
> *語句* → [表達式](./04_Expressions.md#expression) **;**<sub>可選</sub>
>
> *語句* → [聲明](./06_Declarations.md#declaration) **;**<sub>可選</sub>
>
> *語句* → [循環語句](#loop-statement) **;**<sub>可選</sub>
>
> *語句* → [分支語句](#branch-statement) **;**<sub>可選</sub>
>
> *語句* → [帶標簽的語句](#labeled-statement) **;**<sub>可選</sub>
>
> *語句* → [控制轉移語句](#control-transfer-statement) **;**<sub>可選</sub>
>
> *語句* → [defer 語句](#defer-statement) **;**<sub>可選</sub>
>
> *語句* → [do 語句](#do-statement) **:**<sub>可選</sub>
>
> *語句* → [編譯器控制語句](#compiler-control-statement)
>
> *多條語句* → [語句](#statement) [多條語句](#statements)<sub>可選</sub>
## 循環語句 {#loop-statements}
循環語句會根據特定的循環條件來重復執行代碼塊。Swift 提供三種類型的循環語句:`for-in` 語句、`while` 語句和 `repeat-while` 語句。
通過 `break` 語句和 `continue` 語句可以改變循環語句的控制流。有關這兩條語句,詳情參閱 [Break 語句](#break-statement) 和 [Continue 語句](#continue-statement)。
> 循環語句語法
>
>
#### loop-statement {#loop-statement}
> *循環語句* → [for-in 語句](#for-in-statement)
>
> *循環語句* → [while 語句](#while-statement)
>
> *循環語句* → [repeat-while 語句](#repeat-while-statement)
>
### For-In 語句 {#for-in-statements}
`for-in` 語句會為集合(或實現了 [Sequence](https://developer.apple.com/documentation/swift/sequence) 協議的任意類型)中的每一項執行一次代碼塊。
`for-in` 語句的形式如下:
```swift
for item in collection {
statements
}
```
`for-in` 語句在循環開始前會調用集合表達式(`collection expression`)的 `makeIterator()` 方法來獲取一個實現了 [IteratorProtocol](https://developer.apple.com/documentation/swift/iteratorprotocol) 協議的迭代器類型。接下來循環開始,反復調用該迭代器的 `next()` 方法。如果其返回值不是 `nil`,它將會被賦給 `item`,然后執行循環體語句,執行完畢后回到循環開始處,繼續重復這一過程;否則,既不會賦值也不會執行循環體語句,`for-in` 語句至此執行完畢。
> for-in 語句語法
>
>
#### for-in-statement {#for-in-statement}
> *for-in 語句* → **for** **case**<sub>可選</sub> [模式](./08_Patterns.md#pattern) **in** [表達式](./04_Expressions.md#expression) [where 子句](#where-clause)<sub>可選</sub> [代碼塊](./06_Declarations.md#code-block)
>
### While 語句 {#while-statements}
只要循環條件為真,`while` 語句就會重復執行代碼塊。
`while` 語句的形式如下:
```swift
while condition {
statements
}
```
`while` 語句的執行流程如下:
1. 判斷條件(`condition`)的值。如果為 `true`,轉到第 2 步;如果為 `false`,`while` 語句至此執行完畢。
2. 執行循環體中的語句,然后重復第 1 步。
由于會在執行循環體中的語句前判斷條件的值,因此循環體中的語句可能會被執行若干次,也可能一次也不會被執行。
條件的結果必須是 Bool 類型或者 Bool 的橋接類型。另外,條件語句也可以使用可選綁定,請參閱 [可選綁定](../02_language_guide/01_The_Basics.md#optional-binding)。
> while 語句語法
>
>
#### while-statement {#while-statement}
> *while 語句* → **while** [條件子句](#condition-clause) [代碼塊](./06_Declarations.md#code-block)
>
#### condition-clause {#condition-clause}
> *條件子句* → [表達式](./04_Expressions.md#expression) | [表達式](./04_Expressions.md#expression) **,** [條件列表](#condition-list)
>
#### condition {#condition}
> *條件* → [表達式](./04_Expressions.md#expression) |[可用性條件](#availability-condition) | [case 條件](#case-condition) | [可選綁定條件](#optional-binding-condition)
>
>
#### case-condition {#case-condition}
> *case 條件* → **case** [模式](./08_Patterns.md#pattern) [構造器](./06_Declarations.md#initializer)
>
#### optional-binding-condition {#optional-binding-condition}
> *可選綁定條件* → **let** [模式](./08_Patterns.md#pattern) [構造器](./06_Declarations.md#initializer) | **var** [模式](./08_Patterns.md#pattern) [構造器](./06_Declarations.md#initializer)
>
### Repeat-While 語句 {#repeat-while-statements}
`repeat-while` 語句至少執行一次代碼塊,之后只要循環條件為真,就會重復執行代碼塊。
`repeat-while` 語句的形式如下:
```swift
repeat {
statements
} while condition
```
`repeat-while` 語句的執行流程如下:
1. 執行循環體中的語句,然后轉到第 2 步。
2. 判斷條件的值。如果為 `true`,重復第 1 步;如果為 `false`,`repeat-while` 語句至此執行完畢。
由于條件的值是在循環體中的語句執行后才進行判斷,因此循環體中的語句至少會被執行一次。
條件的結果必須是 Bool 類型或者 Bool 的橋接類型。另外,條件語句也可以使用可選綁定,請參閱 [可選綁定](../02_language_guide/01_The_Basics.md#optional-binding)。
> repeat-while 語句語法
>
>
#### repeat-while-statement {#repeat-while-statement}
> *repeat-while 語句* → **repeat** [代碼塊](./06_Declarations.md#code-block) **while** [表達式](./04_Expressions.md#expression)
>
## 分支語句 {#branch-statements}
分支語句會根據一個或者多個條件來執行指定部分的代碼。分支語句中的條件將會決定程序如何分支以及執行哪部分代碼。Swift 提供三種類型的分支語句:`if` 語句、 `guard` 語句和 `switch` 語句。
`if` 語句和 `switch` 語句中的控制流可以用 `break` 語句改變,請參閱 [Break 語句](#break-statement)。
> 分支語句語法
>
>
#### branch-statement {#branch-statement}
> *分支語句* → [if 語句](#if-statement)
>
> *分支語句* → [guard 語句](#guard-statement)
>
> *分支語句* → [switch 語句](#switch-statement)
>
### If 語句 {#if-statements}
`if` 語句會根據一個或多個條件來決定執行哪一塊代碼。
`if` 語句有兩種基本形式,無論哪種形式,都必須有花括號。
第一種形式是當且僅當條件為真時執行代碼,像下面這樣:
```swift
if condition {
statements
}
```
第二種形式是在第一種形式的基礎上添加 `else` 語句(通過引入 `else` 關鍵字),并且用于:當條件為真時執行一部分代碼,當這同一個條件為假的時候執行另一部分代碼。當只有一個 `else` 語句時,`if` 語句具有以下的形式:
```swift
if condition {
statements to execute if condition is true
} else {
statements to execute if condition is false
}
```
`if` 語句的 `else` 語句也可包含另一個 `if` 語句,從而形成一條鏈來測試更多的條件,像下面這樣:
```swift
if condition 1 {
statements to execute if condition 1 is true
} else if condition 2 {
statements to execute if condition 2 is true
} else {
statements to execute if both conditions are false
}
```
`if` 語句中條件的結果必須是 Bool 類型或者 Bool 的橋接類型。另外,條件語句也可以使用可選綁定,請參閱 [可選綁定](../02_language_guide/01_The_Basics.md#optional-binding)。
> if 語句語法
>
>
#### if-statement {#if-statement}
> *if 語句* → **if** [條件子句](#condition-clause) [代碼塊](./06_Declarations.md#code-block) [else 子句](#else-clause)<sub>可選</sub>
>
#### else-clause {#else-clause}
> *else 子句* → **else** [代碼塊](./06_Declarations.md#code-block) | **else** [if 語句](#if-statement)
### Guard 語句 {#guard-statements}
如果一個或者多個條件不成立,可用 `guard` 語句來退出當前作用域。
`guard` 語句的格式如下:
```swift
guard condition else {
statements
}
```
`guard` 語句中條件的結果必須是 Bool 類型或者 Bool 的橋接類型。另外,條件也可以是一條可選綁定,請參閱 [可選綁定](../02_language_guide/01_The_Basics.md#optional-binding)。
在 `guard` 語句中進行可選綁定的任何常量或者變量,其可用范圍從聲明開始直到作用域結束。
`guard` 語句必須有 `else` 子句,而且必須在該子句中調用返回類型是 `Never` 的函數,或者使用下面的語句退出當前作用域:
* `return`
* `break`
* `continue`
* `throw`
關于控制轉移語句,請參閱 [控制轉移語句](#control-transfer-statements)。關于 `Never` 返回類型的函數,請參閱 [永不返回的函數](./06_Declarations.md#rethrowing-functions-and-methods)。
> guard 語句語法
>
>
#### guard-statement {#guard-statement}
> *guard 語句* → **guard** [條件子句](#condition-clause) **else** [代碼塊](./06_Declarations.md#code-block)
### Switch 語句 {#switch-statements}
`switch` 語句會根據控制表達式的值來決定執行哪部分代碼。
`switch` 語句的形式如下:
```swift
switch control expression {
case pattern 1:
statements
case pattern 2 where condition:
statements
case pattern 3 where condition,
pattern 4 where condition:
statements
default:
statements
}
```
`switch` 語句會先計算*控制表達式*的值,然后與每一個 `case` 的模式進行匹配。如果匹配成功,程序將會執行對應的 `case` 中的語句。另外,每一個 `case` 的作用域都不能為空,也就是說在每一個 `case` 的冒號(`:`)后面必須至少有一條語句。如果你不想在匹配到的 `case` 中執行代碼,只需在該 `case` 中寫一條 `break` 語句即可。
可以用作控制表達式的值是十分靈活的。除了標量類型外,如 `Int`、`Character`,你可以使用任何類型的值,包括浮點數、字符串、元組、自定義類型的實例和可選類型。控制表達式的值還可以用來匹配枚舉類型中的成員值或是檢查該值是否包含在指定的 `Range` 中。關于如何在 `switch` 語句中使用這些類型,請參閱 [控制流](../02_language_guide/05_Control_Flow.md) 一章中的 [Switch](../02_language_guide/05_Control_Flow.md#switch)。
每個 `case` 的模式后面可以有一個 `where` 子句。`where` 子句由 `where` 關鍵字緊跟一個提供額外條件的表達式組成。因此,當且僅當控制表達式匹配一個 `case` 的模式且 `where` 子句的表達式為真時,`case` 中的語句才會被執行。在下面的例子中,控制表達式只會匹配包含兩個相等元素的元組,例如 `(1, 1)`:
```swift
case let (x, y) where x == y:
```
正如上面這個例子,也可以在模式中使用 `let`(或 `var`)語句來綁定常量(或變量)。這些常量(或變量)可以在對應的 `where` 子句以及 `case` 中的代碼中使用。但是,如果一個 `case` 中含有多個模式,所有的模式必須包含相同的常量(或變量)綁定,并且每一個綁定的常量(或變量)必須在所有的條件模式中都有相同的類型。
`switch` 語句也可以包含默認分支,使用 `default` 關鍵字表示。只有所有 `case` 都無法匹配控制表達式時,默認分支中的代碼才會被執行。一個 `switch` 語句只能有一個默認分支,而且必須在 `switch` 語句的最后面。
`switch` 語句中 `case` 的匹配順序和源代碼中的書寫順序保持一致。因此,當多個模式都能匹配控制表達式時,只有第一個匹配的 `case` 中的代碼會被執行。
#### Switch 語句必須是詳盡的
在 Swift 中,`switch` 語句中控制表達式的每一個可能的值都必須至少有一個 `case` 與之對應。在某些無法面面俱到的情況下(例如,表達式的類型是 `Int`),你可以使用 `default` 分支滿足該要求。
#### 對未來枚舉的 `case` 進行 `switch` {#future-case}
非凍結枚舉(`nonfronzen enumeration`)是一種特殊的枚舉類型,它可能在未來會增加新的枚舉 `case`,即使這時候你已經編譯并且發布了你的應用,所以在 switch 非凍結枚舉前需要深思熟慮。當一個庫的作者們把一個枚舉標記為非凍結的,這意味著他們保留了增加新的枚舉 `case` 的權利,并且任何和這個枚舉交互的代碼都*必須*在無需重新編譯的條件下能夠處理那些未來可能新加入的 `case` 。只有演進模式的庫代碼、標準庫代碼、用 Swift 實現的 Apple 框架、C 以及 Objective-C 代碼才能夠聲明非凍結枚舉。更多關于凍結和非凍結枚舉的內容,請參閱 [凍結](./07_Attributes.md#frozen)。
當你對未來枚舉進行 switch 時,你總是需要有一個 `default case`,即使每種枚舉類型都已經有對應的 `case` 了。你可以在 default 前標注 `@unknown`,意思是這個 `case` 應該只匹配未來加入的枚舉 `case`。如果你的 `default case` 中匹配了任何在編譯時就能確定的枚舉 `case`,Swift 會拋出一個警告。這可以很好地提醒你庫的作者已經新增了一種 `case`,并且你還沒有去處理。
以下就是一個例子,我們對標準庫的 [Mirror.AncestorRepresentation](https://developer.apple.com/documentation/swift/mirror/ancestorrepresentation) 枚舉進行 switch 操作。每當有新的 `case` 加入,我們會得到一個警告,提示我們要去處理它。
```swift
let representation: Mirror.AncestorRepresentation = .generated
switch representation {
case .customized:
print("Use the nearest ancestor’s implementation.")
case .generated:
print("Generate a default mirror for all ancestor classes.")
case .suppressed:
print("Suppress the representation of all ancestor classes.")
@unknown default:
print("Use a representation that was unknown when this code was compiled.")
}
// Prints "Generate a default mirror for all ancestor classes."
```
#### 不存在隱式落入
當匹配到的 `case` 中的代碼執行完畢后,`switch` 語句會直接退出,而不會繼續執行下一個 `case` 。這就意味著,如果你想執行下一個 `case`,需要顯式地在當前 `case` 中使用 `fallthrough` 語句。關于 `fallthrough` 語句的更多信息,請參閱 [Fallthrough 語句](#fallthrough-statements)。
> switch 語句語法
>
>
#### switch-statement {#switch-statement}
> *switch 語句* → **switch** [表達式](./04_Expressions.md#expression) **{** [switch-case 列表](#switch-cases)<sub>可選</sub> **}**
>
#### switch-cases {#switch-cases}
> *switch case 列表* → [switch-case](#switch-case) [switch-case 列表](#switch-cases)<sub>可選</sub>
>
#### switch-case {#switch-case}
> *switch case* → [case 標簽](#case-label) [多條語句](#statements) | [default 標簽](#default-label) [多條語句](#statements) | [conditional-switch-case](#conditional-switch-case-label)
>
#### case-label {#case-label}
> *case 標簽* → [屬性](#switch-case-attributes-label)<sub>可選</sub> **case** [case 項列表](#case-item-list) **:**
>
#### case-item-list {#case-item-list}
> *case 項列表* → [模式](./08_Patterns.md#pattern) [where 子句](#where-clause)<sub>可選</sub> | [模式](./08_Patterns.md#pattern) [where 子句](#where-clause)<sub>可選</sub> **,** [case 項列表](#case-item-list)
>
#### default-label {#default-label}
> *default 標簽* → [屬性](#switch-case-attributes-label)<sub>可選</sub> **default** **:**
>
>
#### where-clause {#where-clause}
> *where-clause* → **where** [where 表達式](#where-expression)
>
#### where-expression {#where-expression}
> *where-expression* → [表達式](./04_Expressions.md#expression)
>
>
#### grammar-conditional-switch-case {#grammar-conditional-switch-case}
> *conditional-switch-case* → [switch-if-directive-clause](#switch-case-attributes-label) [switch-elseif-directive-clauses](#switch-case-attributes-label) <sub>可選</sub> [switch-else-directive-clause](#switch-case-attributes-label) <sub>可選</sub> [endif-directive](#switch-case-attributes-label)
>
#### grammar-switch-if-directive-clause {#grammar-switch-if-directive-clause}
> *switch-if-directive 語句* → [if-directive](#switch-case-attributes-label) [compilation-condition](#switch-case-attributes-label) [switch-cases](#switch-case-attributes-label) <sub>可選</sub>
>
#### grammar-switch-elseif-directive-clauses {#grammar-switch-elseif-directive-clauses}
> *switch-elseif-directive 語句(復數)* → [elseif-directive-clause](#switch-case-attributes-label) [switch-elseif-directive-clauses](#switch-case-attributes-label)<sub>可選</sub>
>
#### grammar-switch-elseif-directive-clause {#grammar-switch-elseif-directive-clause}
> *switch-elseif-directive 語句* → [elseif-directive](#switch-case-attributes-label) [compilation-condition](#switch-case-attributes-label) [switch-cases](#switch-case-attributes-label)<sub>可選</sub>
>
#### grammar-switch-else-directive-clause {#grammar-switch-else-directive-clause}
> *switch-else-directive 語句* → [else-directive](#switch-case-attributes-label) [switch-cases](#switch-case-attributes-label) <sub>可選</sub>
>
## 帶標簽的語句 {#labeled-statements}
你可以在循環語句或 `switch` 語句前面加上標簽,它由標簽名和緊隨其后的冒號(`:`)組成。在 `break` 和 `continue` 后面跟上標簽名可以顯式地在循環語句或 `switch` 語句中改變相應的控制流。關于這兩條語句用法,請參閱 [Break 語句](#break-statement) 和 [Continue 語句](#continue-statement)。
標簽的作用域在該標簽所標記的語句內。可以嵌套使用帶標簽的語句,但標簽名必須唯一。
關于使用帶標簽的語句的例子,請參閱 [控制流](../02_language_guide/05_Control_Flow.md) 一章中的 [帶標簽的語句](../02_language_guide/05_Control_Flow.md#labeled-statements)。
> 帶標簽的語句語法
>
>
#### labeled-statement {#labeled-statement}
> *帶標簽的語句* → [語句標簽](#statement-label) [循環語句](#grammar-loop-statement)
>
> *帶標簽的語句* → [語句標簽](#statement-label) [if 語句](#if-statement)
>
> *帶標簽的語句* → [語句標簽](#statement-label) [switch 語句](#switch-statement)
>
> > *帶標簽的語句* → [語句標簽](#statement-label) [do 語句](#sdo-statement)
>
#### statement-label {#statement-label}
> *語句標簽* → [標簽名稱](#label-name) **:**
>
#### label-name {#label-name}
> *標簽名稱* → [標識符](./02_Lexical_Structure.md#identifier)
>
## 控制轉移語句 {#control-transfer-statements}
控制轉移語句能夠無條件地把控制權從一片代碼轉移到另一片代碼,從而改變代碼執行的順序。Swift 提供五種類型的控制轉移語句:`break` 語句、`continue` 語句、`fallthrough` 語句、`return` 語句和 `throw` 語句。
> 控制轉移語句語法
>
>
#### control-transfer-statement {#control-transfer-statement}
> *控制轉移語句* → [break 語句](#break-statement)
>
> *控制轉移語句* → [continue 語句](#continue-statement)
>
> *控制轉移語句* → [fallthrough 語句](#fallthrough-statement)
>
> *控制轉移語句* → [return 語句](#return-statement)
>
> *控制轉移語句* → [throw 語句](#throw-statement)
>
### Break 語句 {#break-statement}
`break` 語句用于終止循環語句、`if` 語句或 `switch` 語句的執行。使用 `break` 語句時,可以只寫 `break` 這個關鍵詞,也可以在 `break` 后面跟上標簽名,像下面這樣:
> break
>
> break `label name`
>
當 `break` 語句后面帶標簽名時,可用于終止由這個標簽標記的循環語句、`if` 語句或 `switch` 語句的執行。
而只寫 `break` 時,則會終止 `switch` 語句或 `break` 語句所屬的最內層循環語句的執行。不能使用 `break` 語句來終止未使用標簽的 `if` 語句。
無論哪種情況,控制權都會被轉移給被終止的控制流語句后面的第一行語句。
關于使用 `break` 語句的例子,請參閱 [控制流](../02_language_guide/05_Control_Flow.md) 一章的 [Break](../02_language_guide/05_Control_Flow.md#break) 和 [帶標簽的語句](../02_language_guide/05_Control_Flow.md#labeled-statements)。
> break 語句語法
>
>
#### break-statement {#break-statement}
> *break 語句* → **break** [標簽名稱](#label-name)<sub>可選</sub>
>
### Continue 語句 {#continue-statement}
`continue` 語句用于終止循環中當前迭代的執行,但不會終止該循環的執行。使用 `continue` 語句時,可以只寫 `continue` 這個關鍵詞,也可以在 `continue` 后面跟上標簽名,像下面這樣:
> continue
>
> continue `label name`
>
當 `continue` 語句后面帶標簽名時,可用于終止由這個標簽標記的循環中當前迭代的執行。
而當只寫 `continue` 時,可用于終止 `continue` 語句所屬的最內層循環中當前迭代的執行。
在這兩種情況下,控制權都會被轉移給循環語句的條件語句。
在 `for` 語句中,`continue` 語句執行后,增量表達式還是會被計算,這是因為每次循環體執行完畢后,增量表達式都會被計算。
關于使用 `continue` 語句的例子,請參閱 [控制流](../02_language_guide/05_Control_Flow.md) 一章的 [Continue](../02_language_guide/05_Control_Flow.md#continue) 和 [帶標簽的語句](../02_language_guide/05_Control_Flow.md#labeled-statements)。
> continue 語句語法
>
>
#### continue-statement {#continue-statement}
> *continue 語句* → **continue** [標簽名稱](#label-name)<sub>可選</sub>
>
### Fallthrough 語句 {#fallthrough-statements}
`fallthrough` 語句用于在 `switch` 語句中轉移控制權。`fallthrough` 語句會把控制權從 `switch` 語句中的一個 `case` 轉移到下一個 `case`。這種控制權轉移是無條件的,即使下一個 `case` 的模式與 `switch` 語句的控制表達式的值不匹配。
`fallthrough` 語句可出現在 `switch` 語句中的任意 `case` 中,但不能出現在最后一個 `case` 中。同時,`fallthrough` 語句也不能把控制權轉移到使用了值綁定的 `case`。
關于在 `switch` 語句中使用 `fallthrough` 語句的例子,請參閱 [控制流](../02_language_guide/05_Control_Flow.md) 一章的 [控制轉移語句](../02_language_guide/05_Control_Flow.md#control-transfer-statements)。
> fallthrough 語句語法
>
>
#### fallthrough-statement {#fallthrough-statement}
> *fallthrough 語句* → **fallthrough**
>
### Return 語句 {#return-statements}
`return` 語句用于在函數或方法的實現中將控制權轉移到調用函數或方法,接著程序將會從調用位置繼續向下執行。
使用 `return` 語句時,可以只寫 `return` 這個關鍵詞,也可以在 `return` 后面跟上表達式,像下面這樣:
> return
>
> return `expression`
>
當 `return` 語句后面帶表達式時,表達式的值將會返回給調用函數或方法。如果表達式的值的類型與函數或者方法聲明的返回類型不匹配,Swift 則會在返回表達式的值之前將表達式的值的類型轉換為返回類型。
> 注意
>
>
> 正如 [可失敗構造器](./06_Declarations.md#failable-initializers) 中所描述的,`return nil` 在可失敗構造器中用于表明構造失敗。
>
而只寫 `return` 時,僅僅是從該函數或方法中返回,而不返回任何值(也就是說,函數或方法的返回類型為 `Void` 或者說 `()`)。
> return 語句語法
>
>
#### return-statement {#return-statement}
> *return 語句* → **return** [表達式](./04_Expressions.md#expression)<sub>可選</sub>
### Throw 語句 {#throw-statements}
`throw` 語句出現在拋出函數或者拋出方法體內,或者類型被 `throws` 關鍵字標記的閉包表達式體內。
`throw` 語句使程序在當前作用域結束執行,并向外圍作用域傳播錯誤。拋出的錯誤會一直傳遞,直到被 `do` 語句的 `catch` 子句處理掉。
`throw` 語句由 `throw` 關鍵字緊跟一個表達式組成,如下所示:
> throw `expression`
>
表達式的結果必須符合 `ErrorType` 協議。
關于如何使用 `throw` 語句的例子,請參閱 [錯誤處理](../02_language_guide/17_Error_Handling.md) 一章的 [用 throwing 函數傳遞錯誤](../02_language_guide/17_Error_Handling.md#propagating-errors-using-throwing-functions)。
> throw 語句語法
>
>
#### throw-statement {#throw-statement}
> *throw 語句* → **throw** [表達式](./04_Expressions.md#expression)
>
## Defer 語句 {#defer-statements}
`defer` 語句用于在退出當前作用域之前執行代碼。
`defer` 語句形式如下:
```swift
defer {
statements
}
```
在 `defer` 語句中的語句無論程序控制如何轉移都會被執行。在某些情況下,例如,手動管理資源時,比如關閉文件描述符,或者即使拋出了錯誤也需要執行一些操作時,就可以使用 `defer` 語句。
如果多個 `defer` 語句出現在同一作用域內,那么它們執行的順序與出現的順序相反。給定作用域中的第一個 `defer` 語句,會在最后執行,這意味著代碼中最靠后的 `defer` 語句中引用的資源可以被其他 `defer` 語句清理掉。
```swift
func f() {
defer { print("First") }
defer { print("Second") }
defer { print("Third") }
}
f()
// 打印“Third”
// 打印“Second”
// 打印“First”
```
`defer` 語句中的語句無法將控制權轉移到 `defer` 語句外部。
> defer 語句語法
>
>
#### defer-statement {#defer-statement}
> *延遲語句* → **defer** [代碼塊](./06_Declarations.md#code-block)
>
## Do 語句 {#do-statements}
`do` 語句用于引入一個新的作用域,該作用域中可以含有一個或多個 `catch` 子句,`catch` 子句中定義了一些匹配錯誤條件的模式。`do` 語句作用域內定義的常量和變量只能在 `do` 語句作用域內使用。
Swift 中的 `do` 語句與 C 中限定代碼塊界限的大括號(`{}`)很相似,也并不會降低程序運行時的性能。
`do` 語句的形式如下:
```swift
do {
try expression
statements
} catch pattern 1 {
statements
} catch pattern 2 where condition {
statements
} catch pattern 3, pattern 4 where condition {
statements
} catch {
statements
}
```
如果 `do` 代碼塊中的任何語句拋出了錯誤,程序會跳轉到第一個能模式匹配該錯誤的 `catch` 子句。如果沒有任何子句匹配,錯誤會傳遞到外層作作用域。如果錯誤在最頂層依舊沒有被處理,程序執行會因為運行時錯誤而停止。
如同 `switch` 語句,編譯器會判斷 `catch` 子句是否有遺漏。如果 `catch` 子句沒有遺漏,則認為錯誤已被處理。否則,錯誤會自動傳遞到外層作用域,被某個 `catch` 子句處理掉或者被用 `throws` 關鍵字聲明的拋出函數繼續向外拋出。
擁有多個模式匹配的 `catch` 子句只需其中一個匹配到錯誤即可。如果 `catch` 子句擁有多個模式匹配,所有的模式必須包含相同的綁定常量或變量,并且每個 `catch` 子句里所有綁定的變量或常量的類型必須相同。
為了確保錯誤已經被處理,可以讓 `catch` 子句使用匹配所有錯誤的模式,如通配符模式(`_`)。如果一個 `catch` 子句不指定一種具體模式,`catch` 子句會匹配任何錯誤,并綁定到名為 `error` 的局部常量。有關在 `catch` 子句中使用模式的更多信息,請參閱 [模式](./08_Patterns.md)。
關于如何在 `do` 語句中使用一系列 `catch` 子句的例子,請參閱 [錯誤處理](../02_language_guide/17_Error_Handling.md#handling-errors)。
> do 語句語法
>
>
#### do-statement {#do-statement}
> *do 語句* → **do** [代碼塊](./06_Declarations.md#code-block) [多條 catch 子句](#catch-clauses)<sub>可選</sub>
>
#### catch-clauses {#catch-clauses}
> *多條 catch 子句* → [catch 子句](#catch-clause) [多條 catch 子句](#catch-clauses)<sub>可選</sub>
>
#### catch-clause {#catch-clause}
> *catch 子句* → **catch** [模式](./08_Patterns.md#pattern)<sub>可選</sub> [where 子句](#where-clause)<sub>可選</sub> [代碼塊](./06_Declarations.md#code-block)
#### catch-pattern-list{#catch-pattern-list}
> *catch 模式列表* → [catch 模式](#catch-pattern) | [catch 模式](#catch-pattern) ,[catch 模式列表](#catch-pattern-list)
#### catch-pattern{#catch-pattern}
> *catch 模式* → [模式](./08_Patterns.md#pattern) [where 子句](./05_Statements.md#where-clause)<sub>可選</sub>
## 編譯器控制語句 {#compiler-control-statements}
編譯器控制語句允許程序改變編譯器的行為。Swift 有三種編譯器控制語句:條件編譯語句、線路控制語句和編譯時診斷語句。
> 編譯器控制語句語法
>
>
#### compiler-control-statement {#compiler-control-statement}
> *編譯器控制語句* → [條件編譯語句](#grammar-conditional-compilation-block)
>
> *編譯器控制語句* → [線路控制語句](#line-control-statement)
>
> *編譯器控制語句* → [診斷語句](#grammar-diagnostic-statement)
>
### 條件編譯代碼塊 {#Conditional-Compilation-Block}
條件編譯代碼塊可以根據一個或多個配置來有條件地編譯代碼。
每一個條件編譯代碼塊都以 `#if` 開始,`#endif` 結束。如下:
```swift
#if compilation condition
statements
#endif
```
和 `if` 語句的條件不同,編譯配置的條件是在編譯時進行判斷的。只有編譯配置在編譯時判斷為 `true` 的情況下,相應的語句才會被編譯和執行。
編譯配置可以是 `true` 和 `false` 的字面量,也可以是使用 `-D` 命令行標志的標識符,或者是下列表格中的任意一個平臺檢測函數。
| 函數 | 可用參數 |
| --- | --- |
| `os()` | `OSX`, `iOS`, `watchOS`, `tvOS`, `Linux` |
| `arch()` | `i386`, `x86_64`, `arm`, `arm64` |
| `swift()` | `>=` 或 `<` 后跟版本號 |
| `compiler()` | `>=` 或 `<` 后跟版本號 |
| `canImport()` | 模塊名 |
| `targetEnvironment()` | `simulator`,`macCatalyst` |
在 `swift()` 和 `compiler()` 之后的版本號包含有主版本號,可選副版本號,可選補丁版本號類似,并且用(`.`)來分隔。在比較符和版本號之間不能有空格,版本號與前面的函數相對應,比如 `compiler()` 對應的就是這個編譯器的版本號,`swift()` 對應的就是你要編譯的 `Swift` 語言的版本號。舉個簡單的例子,如果你在使用 `Swift 5` 的編譯器,想編譯 `Swift 4.2` ,可以看下面的例子:
```swift
#if compiler(>=5)
print("Compiled with the Swift 5 compiler or later")
#endif
#if swift(>=4.2)
print("Compiled in Swift 4.2 mode or later")
#endif
#if compiler(>=5) && swift(<5)
print("Compiled with the Swift 5 compiler or later in a Swift mode earlier than 5")
#endif
// 打印 "Compiled with the Swift 5 compiler or later"
// 打印 "Compiled in Swift 4.2 mode or later"
// 打印 "Compiled with the Swift 5 compiler or later in a Swift mode earlier than 5"
```
`canImport()` 后面跟的變量是模塊的名字,這里這個模塊可能并不是每個平臺上都存在的。使用它來檢測是否可以導入這個模塊,如果模塊存在就返回 `true` 否則返回 `false` 。
`targetEnvironment()` 當為模擬器編譯時返回 `true`,否則返回 `false` 。
> 注意
>
>
> `arch(arm)` 平臺檢測函數在 ARM 64 位設備上不會返回 `true`。如果代碼在 32 位的 iOS 模擬器上編譯,`arch(i386)` 平臺檢測函數會返回 `true`。
>
你可以使用邏輯操作符 `&&`、`||` 和 `!` 來組合多個編譯配置,還可以使用圓括號來進行分組。
就像 `if` 語句一樣,你可以使用 `#elseif` 子句來添加任意多個條件分支來測試不同的編譯配置。你也可以使用 `#else` 子句來添加最終的條件分支。包含多個分支的編譯配置語句例子如下:
```swift
#if compilation condition 1
statements to compile if compilation condition 1 is true
#elseif compilation condition 2
statements to compile if compilation condition 2 is true
#else
statements to compile if both compilation conditions are false
#endif
```
> 注意
>
>
> 即使沒有被編譯,編譯配置中的語句仍然會被解析。然而,唯一的例外是編譯配置語句中包含語言版本檢測函數:僅當 `Swift` 編譯器版本和語言版本檢測函數中指定的版本號匹配時,語句才會被解析。這種設定能確保舊的編譯器不會嘗試去解析新 Swift 版本的語法。
>
#### build-config-statement {#build-config-statement}
> 條件編譯代碼塊語法
>
>
#### grammar-conditional-compilation-block {#grammar-conditional-compilation-block}
> *條件編譯代碼塊* → [if-directive 語句](#grammar-if-directive-clause) [elseif-directive 語句(復數)](#grammar-elseif-directive-clauses)<sub>可選</sub> [else-directive 語句](#grammar-else-directive-clause)<sub>可選</sub> [endif-directive](#grammar-endif-directive)
>
#### grammar-if-directive-clause {#grammar-if-directive-clause}
> *if-directive 語句* → [if-directive](#grammar-if-directive) [編譯條件](#compilation-condition) [語句(復數)](#statements)<sub>可選</sub>
>
#### grammar-elseif-directive-clauses {#grammar-elseif-directive-clauses}
> *elseif-directive 語句(復數)* → [elseif-directive 語句](#grammar-elseif-directive-clause) [elseif-directive 語句(復數)](#grammar-elseif-directive-clauses)
>
#### grammar-elseif-directive-clauses {#grammar-elseif-directive-clauses}
> *elseif-directive 語句* → [elseif-directive](#grammar-elseif-directive) [編譯條件](#compilation-condition) [語句(復數)](#statements)<sub>可選</sub>
>
#### grammar-else-directive-clause {#grammar-else-directive-clause}
> *else-directive 語句* → [else-directive](#grammar-else-directive) [語句(復數)](#statements)<sub>可選</sub>
>
> *if-directive* → **#if**
>
> *elseif-directive* → **#elseif**
>
> *else-directive* → **#else**
>
> *endif-directive* → **#endif**
>
#### compilation-condition {#compilation-condition}
> *編譯條件* → [平臺條件](#grammar-platform-condition)
>
> *編譯條件* → [標識符](./02_Lexical_Structure.md#identifier)
>
> *編譯條件* → [布爾值字面量](./02_Lexical_Structure.md#boolean-literal)
>
> *編譯條件* → **(** [編譯條件](#compilation-condition) **)**
>
> *編譯條件* → **!** [編譯條件](#compilation-condition)
>
> *編譯條件* → [編譯條件](#compilation-condition) **&&** [編譯條件](#compilation-condition)
>
> *編譯條件* → [編譯條件](#compilation-condition) **||** [編譯條件](#compilation-condition)
>
#### grammar-platform-condition {#grammar-platform-condition}
#### grammar-platform-condition-os {#grammar-platform-condition-os}
> *平臺條件* → **os ( [操作系統](#operating-system) )**
#### grammar-platform-condition-arch {#grammar-platform-condition-arch}
> *平臺條件* → **arch ( [架構](#architecture) )**
#### grammar-platform-condition-swift {#grammar-platform-condition-swift}
> *平臺條件* → **swift ( >= [swift 版本](#swift-version) )** | **swift ( < [swift 版本](#swift-version) )**
#### grammar-platform-condition-compiler {#grammar-platform-condition-compiler}
> *平臺條件* → **compiler ( >= [swift 版本](#swift-version) )** | **compiler ( < [swift 版本](#swift-version) )**
#### grammar-platform-condition-canImport {#grammar-platform-condition-canImport}
> *平臺條件* → **canImport ( [模塊名](#grammar-module-name) )**
#### grammar-platform-condition-targetEnvironment {#grammar-platform-condition-targetEnvironment}
> *平臺條件* → **targetEnvironment ( [環境](#grammar-environment) )**
#### operating-system {#operating-system}
> *操作系統* → **macOS** | **iOS** | **watchOS** | **tvOS**
>
#### architecture {#architecture}
> *架構* → **i386** | **x86_64** | **arm** | **arm64**
>
#### swift-version {#swift-version}
> *swift 版本* → [十進制數字](./02_Lexical_Structure.md#decimal-digit) -**.** -[swift 版本延續](#grammar-swift-version-continuation) <sub>可選</sub>
#### grammar-swift-version-continuation {#grammar-swift-version-continuation}
> *swift 版本延續* → **.** [十進制數字](./02_Lexical_Structure.md#decimal-digit) [swift 版本延續](#grammar-swift-version-continuation) <sub>可選</sub>
#### grammar-module-name {#grammar-module-name}
> *模塊名* → [identifier](./02_Lexical_Structure.md#identifier)
#### grammar-environment {#grammar-environment}
> *環境* → **模擬器** | **macCatalyst**
### 行控制語句 {#line-control-statements}
行控制語句可以為被編譯的源代碼指定行號和文件名,從而改變源代碼的定位信息,以便進行分析和調試。
行控制語句形式如下:
> #sourceLocation(file: file path, line: line number)
>
> #sourceLocation()
第一種的行控制語句會改變該語句之后的代碼中的字面量表達式 `#line`、 `#file` 和 `#filePath` 所表示的值,從行控制語句里行號的代碼開始。`行號` 是一個大于 0 的整形字面量,會改變 `#line` 表達式的值。`文件名` 是一個字符串字面量,會改變 `#file` 和 `#filePath` 表達式的值。指定的字符串會變成 `#filePath` 的值,且字符串最后的路徑部分會變成 `#file` 的值。
第二種的行控制語句,`#sourceLocation()`,會將源代碼的定位信息重置回默認的行號和文件名。
#### line-control-statement {#line-control-statement}
> 行控制語句語法
>
>*行控制語句* → **#sourceLocation(file:[文件名](#file-name),line:[行號](#line-number))**
>
> *行控制語句* → **#sourceLocation( )**
#### line-number {#line-number}
> *行號* → 大于 0 的十進制整數
>
#### file-name {#file-name}
> *文件名* → [靜態字符串字面量](./02_Lexical_Structure.md#static-string-literal)
### 編譯時診斷語句 {#compile-time-diagnostic-statement}
編譯時診斷語句允許編譯器在編譯的時候可以發出錯誤或者警告。語句形式如下:
```swift
#error("error message")
#warning("warning message")
```
第一句會拋出錯誤信息并終止編譯,第二句會發出警告信息但是編譯會繼續進行。你可以通過靜態字符串字面量來書寫診斷信息,靜態字符串字面量不能使用字符串 `interpolation` 或者 `concatenation`,但可以使用多行的形式。
> 編譯時診斷語句語法
>
>
#### grammar-compile-time-diagnostic-statement {#grammar-compile-time-diagnostic-statement}
> *診斷語句* → **#error** **(** [診斷消息](#grammar-diagnostic-message) **)**
>
> *診斷語句* → **#warning** **(** [診斷消息](#grammar-diagnostic-message) **)**
>
> *診斷語句* → [靜態字符串字面量](./02_Lexical_Structure.md#static-string-literal)
## 可用性條件 {#availability-condition}
可用性條件可作為 `if`,`while`,`guard` 語句的條件,可以在運行時基于特定的平臺參數來查詢 API 的可用性。
可用性條件的形式如下:
```swift
if #available(platform name version, ..., *) {
statements to execute if the APIs are available
} else {
fallback statements to execute if the APIs are unavailable
}
```
使用可用性條件來執行一個代碼塊時,取決于使用的 API 在運行時是否可用,編譯器會根據可用性條件提供的信息來決定是否執行相應的代碼塊。
可用性條件使用一系列逗號分隔的平臺名稱和版本。使用 `iOS`,`OSX`,以及 `watchOS` 等作為平臺名稱,并寫上相應的版本號。`*` 參數是必須寫的,用于處理未來的潛在平臺。可用性條件確保了運行時的平臺不低于條件中指定的平臺版本時才執行代碼塊。
與布爾類型的條件不同,不能用邏輯運算符 `&&` 和 `||` 組合可用性條件。
> 可用性條件語法
>
>
#### availability-condition {#availability-condition}
> *可用性條件* → **#available** **(** [可用性參數列表](#availability-arguments) **)**
#### availability-arguments {#availability-arguments}
> *可用性參數列表* → [可用性參數](#availability-argument) | [可用性參數](#availability-argument) **,** [可用性參數列表](#availability-arguments)
#### availability-argument {#availability-argument}
> *可用性參數* → [平臺名稱](#platform-name) [平臺版本](#platform-version)
>
> *可用性條件* → __*__
>
>
#### platform-name {#platform-name}
> *平臺名稱* → **iOS** | **iOSApplicationExtension**
>
> *平臺名稱* → **OSX** | **macOSApplicationExtension**
>
> *平臺名稱* → **watchOS**
>
> *平臺名稱* → **tvOS**
>
#### platform-version {#platform-version}
> *平臺版本* → [十進制數字](./02_Lexical_Structure.md#decimal-digits)
>
> *平臺版本* → [十進制數字](./02_Lexical_Structure.md#decimal-digits) **.** [十進制數字](./02_Lexical_Structure.md#decimal-digits)
>
> *平臺版本* → [十進制數字](./02_Lexical_Structure.md#decimal-digits) **.** [十進制數字](./02_Lexical_Structure.md#decimal-digits) **.** [十進制數字](./02_Lexical_Structure.md#decimal-digits)
- 1.關于 Swift
- 2.Swift 初見
- 2-1基礎部分
- 2-2基本運算符
- 2-3字符串和字符
- 2-4集合類型
- 2-5控制流
- 2-6函數
- 2-7閉包
- 2-8枚舉
- 2-9類和結構體
- 2-10屬性
- 2-11方法
- 2-12下標
- 2-13繼承
- 2-14構造過程
- 2-15析構過程
- 2-16可選鏈
- 2-17錯誤處理
- 2-18類型轉換
- 2-19嵌套類型
- 2-20擴展
- 2-21協議
- 2-22泛型
- 2-23不透明類型
- 2-24自動引用計數
- 2-25內存安全
- 2-26訪問控制
- 2-27高級運算符
- 3-1關于語言參考
- 3-2詞法結構
- 3-3類型
- 3-4表達式
- 3-5語句
- 3-6聲明
- 3-7特性
- 3-8模式
- 3-9泛型參數
- 4語法總結