控制流
For-In 循环
你可以使用for-in
循环来遍历一个集合中的所有元素,例如数字范围、数组中的元素或者字符串中的字符。
下面的例子用来输出乘 5 乘法表前面一部分内容:
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
区间运算符(Range Operators)
闭区间运算符
闭区间运算符(a...b
)定义一个包含从 a
到 b
(包括 a
和 b
)的所有值的区间。a
的值不能超过 b
。 a...b
数学表达式为[a, b]
半开区间运算符
半开区间(a..<b
)定义一个从 a
到 b
但不包括 b
的区间。 之所以称为半开区间,是因为该区间包含第一个值而不包括最后的值。
a..<b
数学表达式为[a, b)
遍历数组
使用for-in
遍历一个数组所有元素:
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, \(name)!")
}
// Hello, Anna!
// Hello, Alex!
// Hello, Brian!
// Hello, Jack!
根据下标遍历:
for i in 0..<names.count {
print(names[i], i)
}
// Anna 0
// Alex 1
// Brian 2
// Jack 3
你也可以通过遍历一个字典来访问它的键值对。遍历字典时,字典的每项元素会以(key, value)
元组的形式返回,你可以在for-in
循环中使用显式的常量名称来解读(key, value)
元组。下面的例子中,字典的键(key)解读为常量animalName
,字典的值会被解读为常量legCount
:
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
// ants have 6 legs
// cats have 4 legs
// spiders have 8 legs
If
if
语句最简单的形式就是只包含一个条件,只有该条件为true
时,才执行相关代码:
var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
}
// 输出 "It's very cold. Consider wearing a scarf."
和C语言相比去掉了条件语句外面的()
如果想同时满足多个条件可以使用,
分隔:
let i = 9, j = 4, k = 5
if i > j, i > k {
print(i)
}
Switch
switch
语句会尝试把某个值与若干个模式(pattern)进行匹配。根据第一个匹配成功的模式,switch
语句会执行对应的代码。当有可能的情况较多时,通常用switch
语句替换if
语句。
可以匹配字符串:
let someCharacter = "zz"
switch someCharacter {
case "aa":
print("aa")
case "zz":
print("zz")
default:
print("other")
}
// Prints "other"
与 C 和 Objective-C 中的switch
语句不同,在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止switch
语句,而不会继续执行下一个 case 分支。这也就是说,不需要在 case 分支中显式地使用break
语句。这使得switch
语句更安全、更易用,也避免了因忘记写break
语句而产生的错误。
每一个 case 分支都必须包含至少一条语句。像下面这样书写代码是无效的,因为第一个 case 分支是空的:
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // Invalid, the case has an empty body
case "A":
print("The letter A")
default:
print("Not the letter A")
}
// This will report a compile-time error.
不像 C 语言里的switch
语句,在 Swift 中,switch
语句不会一起匹配"a"
和"A"
。相反的,上面的代码会引起编译期错误:case "a": 不包含任何可执行语句
——这就避免了意外地从一个 case 分支贯穿到另外一个,使得代码更安全、也更直观。
为了让单个case同时匹配a
和A
,可以将这个两个值组合成一个复合匹配,并且用逗号分开:
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
print("The letter A")
default:
print("Not the letter A")
}
// Prints "The letter A
区间匹配
case 分支的模式也可以是一个值的区间。下面的例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式:
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
var naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// 输出 "There are dozens of moons orbiting Saturn."
在上例中,approximateCount
在一个switch
声明中被评估。每一个case
都与之进行比较。因为approximateCount
落在了 12 到 100 的区间,所以naturalCount
等于"dozens of"
值,并且此后的执行跳出了switch
语句。
元组(Tuple)
我们可以使用元组在同一个switch
语句中测试多个值。元组中的元素可以是值,也可以是区间。另外,使用下划线(_
)来匹配所有可能的值。
下面的例子展示了如何使用一个(Int, Int)
类型的元组来分类下图中的点(x, y):
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("(0, 0) is at the origin")
case (_, 0):
print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
print("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// 输出 "(1, 1) is inside the box"
不像 C 语言,Swift 允许多个 case 匹配同一个值。实际上,在这个例子中,点(0, 0)可以匹配所有四个 case。但是,如果存在多个匹配,那么只会执行第一个被匹配到的 case 分支。考虑点(0, 0)会首先匹配case (0, 0)
,因此剩下的能够匹配的分支都会被忽视掉。
值绑定(Value Bindings)
case 分支允许将匹配的值绑定到一个临时的常量或变量,并且在case分支体内使用 —— 这种行为被称为值绑定(value binding),因为匹配的值在case分支体内,与临时的常量或变量绑定。
下面的例子展示了如何在一个(Int, Int)
类型的元组中使用值绑定来分类下图中的点(x, y):
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
// 输出 "on the x-axis with an x value of 2"
Where
case 分支的模式可以使用where
语句来判断额外的条件。
下面的例子把下图中的点(x, y)进行了分类:
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
// 输出 "(1, -1) is on the line x == -y"
贯穿(Fallthrough)
Swift 中的switch
不会从上一个 case 分支落入到下一个 case 分支中。相反,只要第一个匹配到的 case 分支完成了它需要执行的语句,整个switch
代码块完成了它的执行。相比之下,C 语言要求你显式地插入break
语句到每个 case 分支的末尾来阻止自动落入到下一个 case 分支中。Swift 的这种避免默认落入到下一个分支中的特性意味着它的switch
功能要比 C 语言的更加清晰和可预测,可以避免无意识地执行多个 case 分支从而引发的错误。
如果你确实需要 C 风格的贯穿的特性,你可以在每个需要该特性的 case 分支中使用fallthrough
关键字。下面的例子使用fallthrough
来创建一个数字的描述语句。
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// 输出 "The number 5 is a prime number, and also an integer."
相当于C语言中case
分支没有使用break
来结束当前的switch
语句