Swift51.com

语句(Statements)


1.0 翻译:coverxit 校对:numbbbbb, coverxit, stanzhai,

2.0 翻译+校对:littledogboy

本页包含内容:

在 Swift 中,有三种类型的语句:简单语句、编译控制语句和控制流语句。简单语句是最常见的,用于构造表达式或者声明。编译控制语句允许程序改变编译器的行为以及包含构建配置和源代码控制语句。

控制流语句则用于控制程序执行的流程,Swift 中有几种类型的控制流语句:循环语句、分支语句和控制传递语句。循环语句用于重复执行代码块;分支语句用于执行满足特定条件的代码块;控制传递语句则用于修改代码的执行顺序。另外,Swift 提供了 do 语句来引入范围以及捕获和处理错误,还提供了 defer 语句在退出当前范围之前执行清理操作。

是否将分号(;)添加到语句的结尾处是可选的。但若要在同一行内写多条独立语句,请务必使用分号。

语句语法
语句表达式 ; 可选
语句声明 ; 可选
语句循环语句 ; 可选
语句分支语句 ; 可选
语句标记语句(Labeled Statement)
语句控制转移语句 ; 可选
语句XXX语句 ; 可选
多条语句(Statements)语句 多条语句(Statements) 可选

循环语句

取决于特定的循环条件,循环语句允许重复执行代码块。Swift 提供四种类型的循环语句:for语句、for-in语句、while语句和do-while语句。

通过break语句和continue语句可以改变循环语句的控制流。有关这两条语句,详情参见 Break 语句Continue 语句

循环语句语法
循环语句for语句
循环语句for-in语句
循环语句while语句
循环语句do-while语句

For 语句

for语句只有在循环条件为真时重复执行代码块,此时计数器递增。

for语句的形式如下:

for initialzation; condition; increment {
statements
}

initialzationconditionincrement 之间的分号,以及包围循环体 statements 的大括号都是不可省略的。

for语句的执行流程如下:

  1. initialzation 循环变量 只会被执行一次,通常用于声明和初始化在接下来的循环中需要使用的变量。
  2. 判断 condition 循环条件: 如果为truestatements 循环体 将会被执行,然后转到第3步。如果为falsestatementsincrement 循环增量 都不会被执行,for至此执行完毕。
  3. 计算 increment 表达式,然后转到第2步。

initialzation 中定义的变量仅在for循环的作用域内有效。condition 表达式的值的类型必须遵循BooleanType协议。

For 循环语法
for语句for for初始条件 可选 ; 表达式 可选 ; 表达式 可选 代码块
for语句for ( for初始条件 可选 ; 表达式 可选 ; 表达式 可选 ) 代码块
for初始条件变量声明 | 表达式列表

For-In 语句

for-in语句允许在重复执行代码块的同时,迭代集合(或遵循Sequence协议的任意类型)中的每一项。

for-in语句的形式如下:

for item in collection {
statements
}

for-in语句在循环开始前会调用 collection 表达式的generate方法来获取一个生成器类型(这是一个遵循Generator协议的类型)的值。接下来循环开始,调用 collection 表达式的next方法。如果其返回值不是None,它将会被赋给 item,然后执行 statements,执行完毕后回到循环开始处;否则,将不会赋值给 item 也不会执行 statementsfor-in至此执行完毕。

For-In 循环语法
for-in语句for 模式 in 表达式 代码块

While 语句

while语句当循环条件为真时,允许重复执行代码块。

while语句的形式如下:

while condition {
statements
}

while语句的执行流程如下:

  1. 计算 condition 表达式: 如果为真true,转到第2步。如果为falsewhile至此执行完毕。
  2. 执行 statements ,然后转到第1步。

由于 condition 的值在 statements 执行前就已计算出,因此while语句中的 statements 可能会被执行若干次,也可能不会被执行。

condition 表达式的值的类型必须遵循BooleanType协议。同时,condition 表达式也可以使用可选绑定,详情参见可选绑定

While 循环语法
while语句while while条件 代码块
条件表达式 | 声明
条件表达式
条件表达式 | 条件列表
条件可用条件 表达式
条件列表条件条件 条件列表
条件可用条件 可选绑定条件
case条件case 模式 构造器 where
可选绑定条件可选绑定头 持续可选绑定 持续可选绑定列表
可选绑定头let 模式 构造器 var 模式 构造器
可持续绑定列表模式 | 构造器 可选绑定头

Repeat-While 语句

repeat-while语句允许代码块被执行一次或多次。

repeat-while语句的形式如下:

repeat {
statements
} while condition

repeat-while语句的执行流程如下:

  1. 执行 statements,然后转到第2步。
  2. 计算 condition 表达式: 如果为true,转到第1步。如果为falserepeat-while至此执行完毕。

由于 condition 表达式的值是在 statements 执行后才计算出,因此repeat-while语句中的 statements 至少会被执行一次。

condition 表达式的值的类型必须遵循BooleanType协议。同时,condition 表达式也可以使用可选绑定,详情参见可选绑定

Repeat-While 循环语法

  • repeat-while语句repeat [代码块](../chapter3/05_Declarations.html#code_block) while [while条件*](../chapter3/10_Statements.html#while_condition)

分支语句

取决于一个或者多个条件的值,分支语句允许程序执行指定部分的代码。显然,分支语句中条件的值将会决定如何分支以及执行哪一块代码。Swift 提供两种类型的分支语句:if语句和switch语句。

switch语句中的控制流可以用break语句修改,详情请见Break 语句

分支语句语法
分支语句if语句
分支语句switch语句

If 语句

取决于一个或多个条件的值,if语句将决定执行哪一块代码。

if语句有两种标准形式,在这两种形式里都必须有大括号。

第一种形式是当且仅当条件为真时执行代码,像下面这样:

if condition {
statements
}

第二种形式是在第一种形式的基础上添加 else 语句,当只有一个 else 语句时,像下面这样:

if condition {
statements to execute if condition is true
} else {
statements to execute if condition is false
}

同时,else 语句也可包含if语句,从而形成一条链来测试更多的条件,像下面这样:

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语句中条件的值的类型必须遵循LogicValue协议。同时,条件也可以使用可选绑定,详情参见可选绑定

If语句语法
if语句if if条件 代码块 else(Clause) 可选
if条件表达式 | 声明
else(Clause)else 代码块 | else if语句

Guard 语句

guard 语句用来转移程序控制出其作用域,如果一个或者多个条件不成立。 guard 语句的格式如下:

guard condition else {
statements
}

guard语句中条件值的类型必须遵循LogicValue协议。且条件可以使用可选绑定,详情参见可选绑定

guard语句中声明的常量或者变量,可用范围从声明开始到作用域结束,常量和变量的值从可选绑定声明中分配。

guard语句需要有else子句,并且必须调用被noreturn属性标记的函数,或者使用下面的语句把程序执行转移到guard语句的作用域外。

  • return
  • break
  • continue
  • throw

执行转移语句详情参见控制传递语句

Switch 语句

取决于switch语句的控制表达式(control expression)switch语句将决定执行哪一块代码。

switch语句的形式如下:

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语句的控制表达式(control expression)会首先被计算,然后与每一个 case 的模式(pattern)进行匹配。如果匹配成功,程序将会执行对应的 case 分支里的 statements。另外,每一个 case 分支都不能为空,也就是说在每一个 case 分支中至少有一条语句。如果你不想在匹配到的 case 分支中执行代码,只需在该分支里写一条break语句即可。

可以用作控制表达式的值是十分灵活的,除了标量类型(scalar types,如IntCharacter)外,你可以使用任何类型的值,包括浮点数、字符串、元组、自定义类的实例和可选(optional)类型,甚至是枚举类型中的成员值和指定的范围(range)等。关于在switch语句中使用这些类型,详情参见控制流一章的 Switch

你可以在模式后面添加一个起保护作用的表达式(guard expression)。起保护作用的表达式是这样构成的:关键字where后面跟着一个作为额外测试条件的表达式。因此,当且仅当控制表达式匹配一个case的某个模式且起保护作用的表达式为真时,对应 case 分支中的 statements 才会被执行。在下面的例子中,控制表达式只会匹配含两个相等元素的元组,如(1, 1)

case let (x, y) where x == y:

正如上面这个例子,也可以在模式中使用let(或var)语句来绑定常量(或变量)。这些常量(或变量)可以在其对应的起保护作用的表达式和其对应的case块里的代码中引用。但是,如果 case 中有多个模式匹配控制表达式,那么这些模式都不能绑定常量(或变量)。

switch语句也可以包含默认(default)分支,只有其它 case 分支都无法匹配控制表达式时,默认分支中的代码才会被执行。一个switch语句只能有一个默认分支,而且必须在switch语句的最后面。

尽管模式匹配操作实际的执行顺序,特别是模式的计算顺序是不可知的,但是 Swift 规定switch语句中的模式匹配的顺序和书写源代码的顺序保持一致。因此,当多个模式含有相同的值且能够匹配控制表达式时,程序只会执行源代码中第一个匹配的 case 分支中的代码。

Switch 语句必须是完备的

在 Swift 中,switch语句中控制表达式的每一个可能的值都必须至少有一个 case 分支与之对应。在某些情况下(例如,表达式的类型是Int),你可以使用默认块满足该要求。

不存在隐式的贯穿(fall through)

当匹配的 case 分支中的代码执行完毕后,程序会终止switch语句,而不会继续执行下一个 case 分支。这就意味着,如果你想执行下一个 case 分支,需要显式地在你需要的 case 分支里使用fallthrough语句。关于fallthrough语句的更多信息,详情参见 Fallthrough 语句

Switch语句语法
switch语句switch 表达式 { SwitchCase列表 可选 }
SwitchCase列表SwitchCase SwitchCase列表 可选
SwitchCasecase标签 多条语句(Statements) | default标签 多条语句(Statements)
SwitchCasecase标签 ; | default标签 ;
case标签case case项列表 :
case项列表模式 guard-clause 可选 | 模式 guard-clause 可选 , case项列表
default标签default :
where-clausewhere guard-expression
where-expression表达式

</a>

带标签的语句

你可以在循环语句或switch语句前面加上标签,它由标签名和紧随其后的冒号(:)组成。在breakcontinue后面跟上标签名可以显式地在循环语句或switch语句中更改控制流,把控制权传递给指定标签标记的语句。关于这两条语句用法,详情参见 Break 语句Continue 语句

标签的作用域是该标签所标记的语句之后的所有语句。你可以不使用带标签的语句,但只要使用它,标签名就必唯一。

关于使用带标签的语句的例子,详情参见控制流一章的带标签的语句

标记语句语法
标记语句(Labeled Statement)语句标签 循环语句 | 语句标签 switch语句
语句标签标签名称 :
标签名称标识符

控制传递语句

通过无条件地把控制权从一片代码传递到另一片代码,控制传递语句能够改变代码执行的顺序。Swift 提供四种类型的控制传递语句:break语句、continue语句、fallthrough语句和return语句。

控制传递语句(Control Transfer Statement) 语法
控制传递语句break语句
控制传递语句continue语句
控制传递语句fallthrough语句
控制传递语句return语句
控制传递语句throw语句

Break 语句

break语句用于终止循环或switch语句的执行。使用break语句时,可以只写break这个关键词,也可以在break后面跟上标签名(label name),像下面这样:

break
break label name

break语句后面带标签名时,可用于终止由这个标签标记的循环或switch语句的执行。

而当只写break时,则会终止switch语句或上下文中包含break语句的最内层循环的执行。

在这两种情况下,控制权都会被传递给循环或switch语句外面的第一行语句。

关于使用break语句的例子,详情参见控制流一章的 Break带标签的语句

Break 语句语法
break语句break 标签名称 可选

Continue 语句

continue语句用于终止循环中当前迭代的执行,但不会终止该循环的执行。使用continue语句时,可以只写continue这个关键词,也可以在continue后面跟上标签名(label name),像下面这样:

continue
continue label name

continue语句后面带标签名时,可用于终止由这个标签标记的循环中当前迭代的执行。

而当只写break时,可用于终止上下文中包含continue语句的最内层循环中当前迭代的执行。

在这两种情况下,控制权都会被传递给循环外面的第一行语句。

for语句中,continue语句执行后,increment 表达式还是会被计算,这是因为每次循环体执行完毕后 increment 表达式都会被计算。

关于使用continue语句的例子,详情参见控制流一章的 Continue带标签的语句

Continue 语句语法
continue语句continue 标签名称 可选

Fallthrough 语句

fallthrough语句用于在switch语句中传递控制权。fallthrough语句会把控制权从switch语句中的一个 case 传递给下一个 case 。这种传递是无条件的,即使下一个 case 的模式与switch语句的控制表达式的值不匹配。

fallthrough语句可出现在switch语句中的任意 case 里,但不能出现在最后一个 case 分支中。同时,fallthrough语句也不能把控制权传递给使用了可选绑定的 case 分支。

关于在switch语句中使用fallthrough语句的例子,详情参见控制流一章的控制传递语句

Fallthrough 语句语法
fallthrough语句fallthrough

Return 语句

return语句用于在函数或方法的实现中将控制权传递给调用者,接着程序将会从调用者的位置继续向下执行。

使用return语句时,可以只写return这个关键词,也可以在return后面跟上表达式,像下面这样:

return
return expression

return语句后面带表达式时,表达式的值将会返回给调用者。如果表达式值的类型与调用者期望的类型不匹配,Swift 则会在返回表达式的值之前将表达式值的类型转换为调用者期望的类型。

而当只写return时,仅仅是将控制权从该函数或方法传递给调用者,而不返回一个值。(这就是说,该函数或方法的返回类型为Void()

Return 语句语法
return语句return 表达式 可选

Availability 语句

可用性条件,被当做ifwhile 语句的条件,并且 guard 语句在运行时会基于特定的语法格式查询接口的可用性。

avaliability 语句的形式如下:

if #available(platform name version,..., *) {
statements to execute if the APIs are available
} else {
fallback statements to execute if the APIs are unavailable
}

可用性条件执行一个代码块时,取决于在运行时想要使用的接口是否可用。 当编译器检查到代码块中的接口是可用的,则从可用性条件中获取相应信息。

可用性条件使用逗号分隔平台名称和版本列表。使用iOSOSX,以及watchOS为平台名称,包括相应的版本号。*参数是必需的。在任何平台上代码块主体都被可用性条件保护起来,由满足最低部署条件的目标设备运行。

与布尔类型条件不同,不能用逻辑运算符 &&|| 合并可用性条件。

可用性条件语法
可用性条件#available ( availability-arguments­ )
可用性条件availability-argument­ | availability-argument­ ,­ availability-arguments­
可用性条件平台名称 版本号
可用性条件*
平台名称iOS | iOSApplicationExtension
平台名称OSX | OSXApplicationExtension­
平台名称watchOS
版本号十进制数字
版本号十进制数字 . 十进制数字
版本号十进制数字 . 十进制数字 . 十进制数字

Throw 语句

throw语句出现在抛出函数或者抛出方法体内,或者类型被throws关键字标记的表达式体内。

throw语句使程序结束执行当前的作用域,并在封闭作用域中传播错误。抛出的错误会一直传播,直到被do语句的catch子句处理掉。

throw语句由throw关键字 跟一个表达式组成 ,如下所示。

throw expression

表达式值的类型必须遵循 LogicValue协议

关于如何使用throw语句的例子,详情参见错误处理一章的抛出错误

throw 语句语法
抛出语句throw 表达式­

Defer 语句

defer 语句用于转移程序控制出延迟语句作用域之前执行代码。

defer 语句中的语句无论程序控制如何转移都会执行。这意味着 defer 语句可以被使用在以下这些情况,像手动得执行资源管理,关闭文件描述,或者即使抛出了错误也需要去实现执行一些动作。

如果多个 defer 语句出现在同一范围内,那么它们执行的顺序与出现的顺序相反。给定作用域中的第一个defer 语句,会在最后执行,这意味着最后执行的延迟语句中的语句涉及的资源可以被其他 defer语句清理掉。

1 func f( ) {
2 defer { print("First") }
3 defer { print("Second") }
4 defer { print("Third") }
5 }
6 f()
7 // prints "Third"
8 // prints "Second"
9 // prints "First"

defer 语句中的语句无法转移程序控制出延迟语句。

defer 语句语法
延迟语句defer 代码块

Do 语句

do 语句用于引入一个新的作用域,该作用域中可以含有一个或多个catch子句,catch子句中定义了一些匹配错误情况的模式。do 语句作用域内定义的常量和变量,只能在do语句作用域内访问。

swift 中的 do 语句与C 中限定代码块界限的大括号 ({})很相似,并且在程序运行的时候并不会造成系统开销。

do {
try expression
statements
} catch pattern 1 {
statements
} catch pattern 2 where condition {
statements
}

如同switch语句,编译器会判断catch子句是否被遗漏。如果catch没有被遗漏,则认为错误被处理。否则,错误会自动传播出包含作用域,被一个封闭的catch语句或抛出函数处理掉,包含函数必须以throws关键字声明。

为了确保错误已经被处理,使用一个匹配所有错误的catch子句,如通配符模式(_)。如果一个catch子句不指定一种模式,catch子句会匹配和约束任何局部变量命名的error。有关在catch子句中使用模式的更多信息,详见模式

关于在一些catch子句中如何使用do语句的例子,详情参见错误处理一章的抛出错误

do 语句语法 → do [代码块](../chapter3/05_Declarations.html#code_block) catch
catch → catch子句 catch子句
catch → catch [模式](../chapter3/07_Patterns.html#pattern)** 可选的 [where]() 可选的 [代码块*](../chapter3/05_Declarations.html#code_block)

编译控制语句

编译控制语句允许程序改变编译器的行为。Swift 有两种编译控制语句:构建配置语句和源代码控制语句。

编译控制语句语法 编译控制语句构建配置语句 编译控制语句源代码控制语句

构建配置语句

构建配置语句可以根据一个或多个配置项来有条件的编译代码。

每一个构建配置语句都以 #if 开始, #endif 结束。如下是一个简单的构建配置语句:

#if build configuration
statements
#endif

if 语句的条件不同,构建配置的条件是在编译时进行判断的。它的结果是:只有构建配置在编译时判断为 true 的情况下语句才会被编译和执行。

构建配置 可以是 truefalse 的常量,也可以是使用 -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­

源代码控制语句

源代码控制语句用来给被编译源代码指定一个与原始行号和文件名不同的行号和文件名。使用源代码控制语句可以改变 Swift 使用源代码的位置,以便进行分析和测试。

源代码的控制语句的例子如下:

#line line number filename

源代码控制语句改变了常量表达式 __LINE____FILE__ 的值,以一行源代码开头,然后跟着源代码控制语句。line number 改变了 __LINE__ 的值,它是一个大于 0 的常量。filename 改变了 __FILE__ 的值,它是一个字符串常量。

你可以通过写一句不指定 line numberfilename 的源代码控制语句来吧源代码的位置回退到初始的行号和文件。

源代码控制语句必须出现在源代码的那一行,而且不能是源代码文件的最后一行。

源代码控制语句

源代码控制语句 → #line­ 源代码控制语句 → #line­ line-number­ file-name­ line-number → 大于 0 的十进制数 file-name → 字符串常量