语句(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
}
initialzation、condition 和 increment 之间的分号,以及包围循环体 statements 的大括号都是不可省略的。
for
语句的执行流程如下:
- initialzation 循环变量 只会被执行一次,通常用于声明和初始化在接下来的循环中需要使用的变量。
- 判断 condition 循环条件: 如果为
true
,statements 循环体 将会被执行,然后转到第3步。如果为false
,statements 和 increment 循环增量 都不会被执行,for
至此执行完毕。 - 计算 increment 表达式,然后转到第2步。
在 initialzation 中定义的变量仅在for
循环的作用域内有效。condition 表达式的值的类型必须遵循BooleanType
协议。
For 循环语法
for语句 → for for初始条件 可选 ; 表达式 可选 ; 表达式 可选 代码块
for语句 → for ( for初始条件 可选 ; 表达式 可选 ; 表达式 可选 ) 代码块
for初始条件 → 变量声明 | 表达式列表
For-In 语句
for-in
语句允许在重复执行代码块的同时,迭代集合(或遵循Sequence
协议的任意类型)中的每一项。
for-in
语句的形式如下:
for
item
incollection
{
statements
}
for-in
语句在循环开始前会调用 collection 表达式的generate
方法来获取一个生成器类型(这是一个遵循Generator
协议的类型)的值。接下来循环开始,调用 collection 表达式的next
方法。如果其返回值不是None
,它将会被赋给 item,然后执行 statements,执行完毕后回到循环开始处;否则,将不会赋值给 item 也不会执行 statements,for-in
至此执行完毕。
While 语句
while
语句当循环条件为真时,允许重复执行代码块。
while
语句的形式如下:
while
condition
{
statements
}
while
语句的执行流程如下:
- 计算 condition 表达式: 如果为真
true
,转到第2步。如果为false
,while
至此执行完毕。 - 执行 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
} whilecondition
repeat-while
语句的执行流程如下:
- 执行 statements,然后转到第2步。
- 计算 condition 表达式: 如果为
true
,转到第1步。如果为false
,repeat-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 语句
取决于一个或多个条件的值,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 ifcondition 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
{
casepattern 1
:
statements
casepattern 2
wherecondition
:
statements
casepattern 3
wherecondition
,
pattern 4
wherecondition
:
statements
default:
statements
}
switch
语句的控制表达式(control expression)会首先被计算,然后与每一个 case 的模式(pattern)进行匹配。如果匹配成功,程序将会执行对应的 case 分支里的 statements。另外,每一个 case 分支都不能为空,也就是说在每一个 case 分支中至少有一条语句。如果你不想在匹配到的 case 分支中执行代码,只需在该分支里写一条break
语句即可。
可以用作控制表达式的值是十分灵活的,除了标量类型(scalar types,如Int
、Character
)外,你可以使用任何类型的值,包括浮点数、字符串、元组、自定义类的实例和可选(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列表 可选
SwitchCase → case标签 多条语句(Statements) | default标签 多条语句(Statements)
SwitchCase → case标签 ; | default标签 ;
case标签 → case case项列表 :
case项列表 → 模式 guard-clause 可选 | 模式 guard-clause 可选 , case项列表
default标签 → default :
where-clause → where guard-expression
where-expression → 表达式
带标签的语句
你可以在循环语句或switch
语句前面加上标签,它由标签名和紧随其后的冒号(:)组成。在break
和continue
后面跟上标签名可以显式地在循环语句或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
breaklabel name
当break
语句后面带标签名时,可用于终止由这个标签标记的循环或switch
语句的执行。
而当只写break
时,则会终止switch
语句或上下文中包含break
语句的最内层循环的执行。
在这两种情况下,控制权都会被传递给循环或switch
语句外面的第一行语句。
关于使用break
语句的例子,详情参见控制流一章的 Break 和带标签的语句。
Break 语句语法
break语句 → break 标签名称 可选
Continue 语句
continue
语句用于终止循环中当前迭代的执行,但不会终止该循环的执行。使用continue
语句时,可以只写continue
这个关键词,也可以在continue
后面跟上标签名(label name),像下面这样:
continue
continuelabel 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
returnexpression
当return
语句后面带表达式时,表达式的值将会返回给调用者。如果表达式值的类型与调用者期望的类型不匹配,Swift 则会在返回表达式的值之前将表达式值的类型转换为调用者期望的类型。
而当只写return
时,仅仅是将控制权从该函数或方法传递给调用者,而不返回一个值。(这就是说,该函数或方法的返回类型为Void
或()
)
Return 语句语法
return语句 → return 表达式 可选
Availability 语句
可用性条件,被当做if
,while
语句的条件,并且 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
}
可用性条件执行一个代码块时,取决于在运行时想要使用的接口是否可用。 当编译器检查到代码块中的接口是可用的,则从可用性条件中获取相应信息。
可用性条件使用逗号分隔平台名称和版本列表。使用iOS
,OSX
,以及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 {
tryexpression
statements
} catchpattern 1
{
statements
} catchpattern 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
的情况下语句才会被编译和执行。
构建配置 可以是 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
源代码控制语句
源代码控制语句用来给被编译源代码指定一个与原始行号和文件名不同的行号和文件名。使用源代码控制语句可以改变 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 → 字符串常量