告诉计算机在什么时候该做什么,称做控制流。
在本教程中,您将学习如何来控制流程,从而让计算机听你的话。您还将了解布尔值true
和false
,以及如何使用它们来比较数据。
入门
此前学过了一些类型如Int
,Double
和String
。在这里,您将学习另一种类型:布尔。
如,查找两个数字中的较大者,答案是true或false。
let yes = true // 类型推断为Bool
let no = false // 类型推断为Bool
布尔类型的值只能是true
或false
。
布尔运算符
布尔值通常用于比较值。例如,您可能有两个值,并且您想知道它们是否相等:值是相同的(true)还是它们是不同的(false)。
在Swift中,使用==执行此操作:
let doesOneEqualTwo = (1 == 2)
swift推断doesOneEqualTwo
是一个Bool
。显然,1不等于2,因此doesOneEqualTwo
将是false
。
同样,你可以看看两个值是否不相等:
let doesOneNotEqualTwo = (1 != 2)
因为1不等于2,所以doesOneNotEqualTwo
会是true
。
!
叫取反操作。
大于(>
),小于(<
):
let isOneGreaterThanTwo = (1 > 2)
let isOneLessThanTwo = (1 < 2)
isOneGreaterThanTwo
为false
,isOneLessThanTwo
为true
。
另外还有小于等于和大于等于:<=
,>=
,同理。
布尔逻辑
且&&
。如果两个都是true
,结果才是true
。否则,结果是false
。
let and = true && true
在这种情况下,and
将是true
。如果右边的任何一个值是false
,那么and
就是false
。
或||
。只要其中一个为true,则结果为true。
let or = true || false
在这种情况下,or
将是true
。如果右边的两个值都是false
,那么or
就是false
。如果两者都是true
,那么or
仍然是true
。
在Swift中,布尔逻辑通常应用于多个条件:
let andTrue = 1 < 2 && 4 > 3
let andFalse = 1 < 2 && 3 > 4
let orTrue = 1 < 2 || 3 > 4
let orFalse = 1 == 2 || 3 == 4
也可以这样:
let andOr = (1 < 2 && 3 > 4) || 1 < 4
字符串比较
在Swift,用于比较数字是否相等的==
号也可以用来比较字符串:
let guess = "dog"
let dogEqualsCat = guess == "cat"
得出dogEqualsCat
是一个布尔类型,为false
。
与数字一样,您不仅可以比较是否相等,还可以比较一个值是否大于或小于另一个值:
let order = "cat" < "dog"
这时是按英文字母顺序比较,order
为true
if语句
流程控制的第一个也是最常见的是if
,只有当某个条件为true
时才执行:
if 2 > 1 {
print("Yes, 2 is greater than 1.")
}
这是一个简单的if
语句。如果条件是true
,则将执行大括号之间的代码。如果条件为false
,则语句将不执行大括号之间的代码。
您可以扩展if
语句:
let animal = "Fox"
if animal == "Cat" || animal == "Dog" {
print("Animal is a house pet.")
} else {
print("Animal is not a house pet.")
}
这里,如果animal
等于"Cat"
或者"Dog"
,那么语句将运行第一个代码块。如果animal
不等于"Cat"
或者"Dog"
,则将在else
内运行,以下内容被打印到控制台:
Animal is not a house pet.
else if
:
let hourOfDay = 12
var timeOfDay = ""
if hourOfDay < 6 {
timeOfDay = "Early morning"
} else if hourOfDay < 12 {
timeOfDay = "Morning"
} else if hourOfDay < 17 {
timeOfDay = "Afternoon"
} else if hourOfDay < 20 {
timeOfDay = "Evening"
} else if hourOfDay < 24 {
timeOfDay = "Late evening"
} else {
timeOfDay = "INVALID HOUR!"
}
print(timeOfDay)
if
语句将逐个测试多个条件,直到true
。无论后面的else-if
条件是否为true,仅执行第一条true
后面的代码。
末尾的else
子句来处理以上都为false
的情况。
控制台将打印出以下内容:
Afternoon
封装变量
if
语句引入了一个新的概念范围,这是一种通过使用大括号封装变量的方法。
如,某地兼职工资的规定为:在40小时之前每小时25美元,之后每小时50美元。
通过以下方式计算您的工资:
var hoursWorked = 45
var price = 0
if hoursWorked > 40 {
let hoursOver40 = hoursWorked - 40
price += hoursOver40 * 50
hoursWorked -= hoursOver40
}
price += hoursWorked * 25
print(price)
结果如下:
1250
hoursOver40
是在if
语句中声明的新常量。如果这样会发生什么?
// ...
print(price)
print(hoursOver40)
这将导致以下错误:
Use of unresolved identifier 'hoursOver40'
此错误通知您,您只能在创建它的范围内使用hoursOver40
常量。在这种情况下,if
语句创建了一个新范围,因此当该范围结束后,您将无法使用该常量。
但是,每个范围都可以使用其父范围中的变量和常量。在上面的示例中,if
语句内部仍然可以使用您在父范围中创建的price
和hoursWorked
变量。
三元运算
三元运算符即返回两个值中的一个,这取决于条件是true
还是false
:
(<CONDITION>) ? <TRUE VALUE> : <FALSE VALUE>
这是一个找出两个变量中最小值的示例:
let a = 5
let b = 10
let min: Int
if a < b {
min = a
} else {
min = b
}
感谢三元运算符,您可以重写为简洁的代码:
let a = 5
let b = 10
let min = a < b ? a : b
如果a < b
是true
,则min
的值为a
;如果是false
,min
为b
。
注意:如果过度使用,可能会牺牲代码的易读性。
循环
循环是多次执行代码的一种方式。在本节中,您将了解while
循环。
循环时
当while
后面条件为true
时,将循环执行大括号中的代码:
while <CONDITION> {
<LOOP CODE>
}
每一次循环,都会先检查条件。如果条件是true
,则执行并准备下一次循环。一旦条件为false
,则循环停止。就像if
语句一样,while
循环也引入了一个范围(大括号中的代码)。
最简单的while
循环:
while true {
}
这是一个永远不会结束的while
循环(死循环),因为条件总是true
。一个死循环可能不会让程序崩溃,但很可能会让计算机死机。
一个while
循环示例:
var sum = 1
while sum < 1000 {
sum = sum + (sum + 1)
}
此代码计算一个数学序列,直到sum
值大于1000
。
循环执行如下:
在第九次迭代(循环)之后,sum
是1023
,循环条件sum < 1000
变为false
,循环停止。
repeat-while循环
它与while
循环的不同之处在于,在循环结束时判断条件是否为true
:
repeat {
<LOOP CODE>
} while <CONDITION>
这是上一节的示例,使用repeat-while
循环:
sum = 1
repeat {
sum = sum + (sum + 1)
} while sum < 1000
在此示例中,结果和之前相同。但并非所有的时候都是一样的。
while
循环:
sum = 1
while sum < 1 {
sum = sum + (sum + 1)
}
repeat-while
循环:
sum = 1
repeat {
sum = sum + (sum + 1)
}while sum < 1
在while
循环中,条件从一开始就是false
。说明不会执行循环体,sum
最终为1
。
在repeat-while
中,sum
为3
,因为循环体将先执行一次。
跳出循环
有时你想早点结束循环。可以使用break
语句,该语句会立即停止循环并继续循环后面的代码:
sum = 1
while true {
sum = sum + (sum + 1)
if sum >= 1000 {
break
}
}
条件为true
,所以会永远循环。但一旦sum
大于或等于1000
,循环将结束。
高级控制流
在本节中,您将继续学习如何控制代码执行。您将了解另一个称为for
循环的循环。
范围
在深入了解for
循环语句之前,您需要了解一下ClosedRange
和Range
类型,它们可以表示一系列的数字。
封闭的范围:
let closedRange = 0...5
三个点(...
)表示范围是从0到5(包括0和5)。即0, 1, 2, 3, 4, 5
。
半开放范围:
let halfOpenRange = 0..<5
范围是从0到5,包括0但不包括5。即0, 1, 2, 3, 4
。
注意:
第二个数字必须始终大于或等于第一个数字。
范围通常用于for
循环和switch
语句中!
for循环
for <CONSTANT> in <RANGE> {
<LOOP CODE>
}
循环以for
关键字开头,后面跟一个想在循环中使用的常量名,in
后面为循环的范围:
let count = 10
var sum = 0
for i in 1...count {
sum += i
}
i
的初始值为1,也就是范围(1...count
)的第一个数,每次循环之后都加1,直到等于count
为止。
以下是每次迭代的i
和sum
的值:
i
循环外部不可用。
当你在循环中不需要使用i
时,可以用下划线:
sum = 1
var lastSum = 0
for _ in 0..<count {
let temp = sum
sum = sum + lastSum
lastSum = temp
}
只是单纯的想让代码执行一定的次数,不需要用到循环常量(上述i
)。
0..<count
半开,表示代码将执行count
次,这是一种需要执行多少次的常用方法。
也可以仅在某些条件下执行循环。如,想要计算总和但仅针对奇数:
var sum = 0
for i in 1...count where i % 2 == 1 {
sum += i
}
where
为for
循环中的一个子句。循环只会在where
条件为true
时执行循环体。
continue声明
有时你想跳过特定情况的循环迭代,而不想完全跳出循环。可以使用continue
语句,该语句立即结束循环的当前迭代并开始下一次迭代。
8✕8乘法表:
假设您想要计算所有单元格的总和但排除所有偶数行:
使用for
循环:
sum = 0
for row in 0..<8 {
if row % 2 == 0 {
continue
}
for column in 0..<8 {
sum += row * column
}
}
模2为0时,该行是偶数行。在这种情况下,continue
跳出本次for
循环,执行下一次循环。
和break
一样,continue
也适用于for
循环和while
循环。
switch语句
控制流的另一种是switch
语句,它允许您根据变量或常量的值执行不同的代码。
一个非常简单的switch
语句:
let number = 10
switch number {
case 0:
print("Zero")
default:
print("Non-zero")
}
将输出:
Non-zero
case
后面的值(本例中为0
)表示:当number
为此值时,执行冒号后面的语句。default
表示以上全没有匹配到的话执行下面的代码。
另一个例子:
switch number {
case 10:
print("It's ten!")
default:
break
}
这次匹配到10,将执行case下面的代码。
break
表示什么都不执行,
switch
语句适用于任何数据类型!以下是切换字符串的示例:
let string = "Dog"
switch string {
case "Cat", "Dog":
print("Animal is a house pet.")
default:
print("Animal is not a house pet.")
}
这将打印以下内容:
Animal is a house pet.
case
后接两个值,这说明如果等于"Cat"
或者"Dog"
将执行。
高级switch语句
case
后接多种情况:
let hourOfDay = 12
var timeOfDay = ""
switch hourOfDay {
case 0, 1, 2, 3, 4, 5:
timeOfDay = "Early morning"
case 6, 7, 8, 9, 10, 11:
timeOfDay = "Morning"
case 12, 13, 14, 15, 16:
timeOfDay = "Afternoon"
case 17, 18, 19:
timeOfDay = "Evening"
case 20, 21, 22, 23:
timeOfDay = "Late evening"
default:
timeOfDay = "INVALID HOUR!"
}
print(timeOfDay)
将输出以下内容:
Afternoon
可以使用范围让代码更简洁:
var timeOfDay2 = ""
switch hourOfDay {
case 0...5:
timeOfDay2 = "Early morning"
case 6...11:
timeOfDay2 = "Morning"
case 12...16:
timeOfDay2 = "Afternoon"
case 17...19:
timeOfDay2 = "Evening"
case 20..<24:
timeOfDay2 = "Late evening"
default:
timeOfDay2 = "INVALID HOUR!"
}
print(timeOfDay2)
也可以像for循环一样使用where
子句(先声明一个常量以便where子句中使用):
switch number {
case let x where x % 2 == 0:
print("Even")
default:
print("Odd")
}
这将打印以下内容:
Even
如for循环一样,声明的常量在下面的代码中不需要使用的话,可以用下划线代替:
switch number {
case _ where number % 2 == 0:
print("Even")
default:
print("Odd")
}
部分匹配
let coordinates = (x: 3, y: 2, z: 5)
switch coordinates {
case (0, 0, 0): // 1
print("Origin")
case (_, 0, 0): // 2
print("On the x-axis.")
case (0, _, 0): // 3
print("On the y-axis.")
case (0, 0, _): // 4
print("On the z-axis.")
default: // 5
print("Somewhere in space")
}
该switch
语句使用部分匹配:
- 精确匹配
(0, 0, 0)
。说明时3D空间的原点。 - 匹配y = 0,z = 0和x可为任何值。说明坐标位于x轴上。
- 匹配x = 0,z = 0和y可为任何值。说明坐标位于y轴上。
- 匹配x = 0,y = 0和z可为任何值。说明坐标位于z轴上。
- 匹配其余坐标。
把上例中的下划线声明为变量,这样可以在case后面的语句中使用:
switch coordinates {
case (0, 0, 0):
print("Origin")
case (let x, 0, 0):
print("On the x-axis at x = \(x)")
case (0, let y, 0):
print("On the y-axis at y = \(y)")
case (0, 0, let z):
print("On the z-axis at z = \(z)")
case let (x, y, z):
print("Somewhere in space at x = \(x), y = \(y), z = \(z)")
}
使用let
语法来提取相关值。然后使用字符串插值打印出来。
此switch
语句中没有default
选项。因为已经穷举了所有情况,所以不用写默认值。
注:想提取元组的所有值时,let (x, y, z)
和(let x, let y, let z)
一样。
最后,可以使用let-where
语法来匹配更复杂的情况:
switch coordinates {
case let (x, y, _) where y == x:
print("Along the y = x line.")
case let (x, y, _) where y == x * x:
print("Along the y = x^2 line.")
default:
break
}