Swift 条件语句
条件语句根据一个或多个条件的真假,决定执行哪一段代码。
Swift 提供了 if、switch、guard 和三元运算符,它们的共同前提是条件必须是 Bool。
if 语句
if 语句由一个布尔条件和一段代码块组成,条件为 true 时才执行代码块。
实例
if varA < 20 {
print("varA 小于 20")
}
print("varA 变量的值为 \(varA)")
}
checkIf(10)
以上程序执行结果为:
varA 小于 20 varA 变量的值为 10
注意 if 后面的大括号不能省略,即使代码块里只有一行。
if-else 与 else if 链
if 后面可以跟一个 else,条件为 false 时执行 else 分支。
实例
if varA < 20 {
print("varA 小于 20")
} else {
print("varA 大于或等于 20")
}
}
checkIfElse(100)
以上程序执行结果为:
varA 大于或等于 20
需要判断多个条件时,用 else if 串成一条链,一旦某个分支命中,后面的分支就都不会再执行。
实例
if score == 20 {
print("score 的值为 20")
} else if score == 50 {
print("score 的值为 50")
} else if score >= 80 {
print("score 大于等于 80")
} else {
print("没有匹配条件")
}
}
checkChain(85)
以上程序执行结果为:
score 大于等于 80
嵌套 if
if 或 else if 的代码块里可以再写 if,形成嵌套判断。
实例
if n1 == 100 {
print("第一个条件为 true")
if n2 == 200 {
print("第二个条件也是 true")
}
}
}
checkNested(100, 200)
以上程序执行结果为:
第一个条件为 true 第二个条件也是 true
嵌套层数太多会降低可读性,这时通常改用 guard 提前退出,或者把判断抽成独立的函数。
条件必须是 Bool
Swift 要求条件位置放一个真正的 Bool,整数、字符串、可选值都不能直接当条件。
实例
if count > 0 { // 用比较运算得到 Bool
print("count 是正数")
}
if flag { // flag 本身就是 Bool
print("flag 为 true")
}
}
checkBool(3, flag: true)
以上程序执行结果为:
count 是正数 flag 为 true
把整数直接当条件会编译失败。
实例
if count {
print("count 非零")
}
编译器给出的错误是:
error: type 'Int' cannot be used as a boolean; test for '!= 0' instead
注意:Swift 没有 C 语言那种「0、空字符串、空指针为假」的隐式转换,也没有 not 关键字,取反要用 !。可选值想当条件用,必须先解包,写法见第 29 篇《Swift 可选类型》。
三元运算符
条件 ? 值1 : 值2 是 if-else 的表达式版本,适合在两个值之间二选一。
实例
return age >= 18 ? "可以投票" : "不能投票"
}
print(voteText(20))
print(voteText(15))
以上程序执行结果为:
可以投票 不能投票
三元表达式嵌套太多会难读,超过两层时建议改回 if-else。
switch 语句
switch 把一个值和若干 case 逐一比对,命中后执行对应分支。
和 C 语言不同,Swift 的 case 执行完会自动结束,不需要写 break,也不会掉进下一个 case。
区间匹配
case 里可以直接写区间,用来给分数、年龄这类连续值分档。
实例
switch grade {
case 90...100:
return "优秀"
case 80..<90:
return "良好"
case 60..<80:
return "及格"
default:
return "不及格"
}
}
print(gradeText(85))
以上程序执行结果为:
良好
元组匹配
把多个值组合成元组,再用带模式的 case 一次性匹配多个维度,下划线 _ 表示这一位不关心。
实例
switch coord {
case (0, 0):
return "原点"
case (_, 0):
return "在 x 轴上"
case (0, _):
return "在 y 轴上"
default:
return "其他位置"
}
}
print(axisText((0, 5)))
以上程序执行结果为:
在 y 轴上
值绑定与 where
用 case let (x, y) 可以把匹配到的值绑定到局部常量,再用 where 追加额外条件。
实例
switch point {
case let (x, y) where x == y:
return "(\(x), \(y)) 在主对角线上"
case let (x, y) where x == -y:
return "(\(x), \(y)) 在反对角线上"
case let (x, y):
return "(\(x), \(y)) 是普通点"
}
}
print(diagonalText((3, -3)))
以上程序执行结果为:
(3, -3) 在反对角线上
多值匹配与 default
一个 case 里可以列出多个用逗号分隔的值,命中任意一个即可。
实例
switch index {
case 100:
return "index 的值为 100"
case 10, 15:
return "index 的值为 10 或 15"
case 5:
return "index 的值为 5"
default:
return "默认 case"
}
}
print(indexText(10))
以上程序执行结果为:
index 的值为 10 或 15
注意:只有当 switch 已经穷尽所有可能时才能省略 default。对 Int 这类取值无限的类型必须写 default;对 Bool 或已列出全部成员的枚举,则可以省略。
实例
func boolText(_ flag: Bool) -> String {
switch flag {
case true:
return "真"
case false:
return "假"
}
}
print(boolText(true), boolText(false))
以上程序执行结果为:
真 假
@unknown default
当 switch 的值来自另一个模块的枚举时,那个枚举未来可能新增成员,这时用 @unknown default 兜底。
实例
switch direction {
case .north:
print("北")
case .south:
print("南")
@unknown default:
print("未知方向")
}
上面这段代码无法单独运行,因为 direction 的类型需要由外部模块提供。
@unknown default 的作用是:新版本枚举增加成员时,编译器会给出警告提醒你去处理,而不是直接编译失败。
注意:如果枚举就定义在同一个文件里,编译器已经知道它的全部成员,此时写 @unknown default 并不能消掉「switch must be exhaustive」警告,仍然要把所有 case 列全,所以同一模块内直接用 default 即可。
fallthrough
默认情况下,Swift 的 case 执行完就结束;如果确实想继续执行下一个 case 的代码,要显式写 fallthrough。
实例
switch idx {
case 100:
print("index 的值为 100")
case 10, 15:
print("index 的值为 10 或 15")
fallthrough
case 5:
print("index 的值为 5")
default:
print("默认 case")
}
}
fallthroughDemo(10)
以上程序执行结果为:
index 的值为 10 或 15 index 的值为 5
注意:fallthrough 不会再做任何条件判断,直接进入下一个 case 的代码块。它只能掉进普通的 case;如果下一个 case 需要绑定变量,编译器会报 'fallthrough' from a case which doesn't bind variable。
guard 提前退出
guard 用来在条件不满足时提前离开当前作用域,它的 else 分支必须跳出(return、break、continue 或 throw)。
把不满足的情况放在前面挡掉,主逻辑就能少一层缩进,读起来更顺。
实例
guard age >= 18 else {
return "未成年,不能进入"
}
return "已成年,欢迎进入"
}
print(checkAge(20))
print(checkAge(15))
以上程序执行结果为:
已成年,欢迎进入 未成年,不能进入
guard let 是它最常用的形态:解包可选值,失败就退出,成功则解包后的常量在后续代码中一直可用。
实例
guard let name = name, !name.isEmpty else {
return "你好,游客"
}
// 到这里 name 已经是非空的 String
return "你好,\(name)"
}
print(greet("Runoob"))
print(greet(nil))
以上程序执行结果为:
你好,Runoob 你好,游客
常见问题
下面几个问题在写条件语句时最常遇到。
| 问题 | 说明 |
|---|---|
if 1 { } 为什么报错 | 条件必须是 Bool,改成 if 1 != 0 { } |
switch 的 default 能省略吗 | 穷尽时可以;Int 这类必须写 |
case 后面要写 break 吗 | 不用,Swift 默认不会往下掉 |
guard 和 if 怎么选 | 需要提前退出、减少缩进时用 guard;只是分支选择时用 if |
guard 里能声明变量吗 | 可以,但声明的变量在 guard 之后依然可用,这是它和 if let 的主要区别 |
