在上一文中,你学习了如何使用if语句
和while循环
的决策能力来控制执行流程。 在本章中,你将继续学习如何控制执行流程。 你将了解另一个称为for循环的循环。
循环听起来可能不太有趣,但在计算机程序中很常见。 例如,你可能具有从云下载图像的代码。 通过循环,你可以运行多次以下载整个照片库。 或者,如果你的游戏包含多个由计算机控制的角色,则可能需要循环遍历每个角色,并确保它知道接下来要做什么。
你还将了解switch语句,在Swift中它特别强大。 他们让你检查一个值并根据该值决定要做什么。 与某些高级Swift功能
(例如模式匹配
)一起使用时,它们的功能异常强大。
可数范围
在深入研究for循环语句之前,你需要了解Countable Range数据类型
,该数据类型使你可以表示一系列可计数的整数。 让我们看一下两种类型的范围。
首先,存在可数的封闭范围,你可以这样表示:
1 | let closedRange = 0...5 |
三个点(…)表示此范围已关闭,这意味着范围从0到5(含)。 这就是数字(0、1、2、3、4、5)。
其次,有很多可打开的半开范围,你可以这样表示:
1 | let halfOpenRange = 0..<5 |
在这里,将三个点替换为两个点和一个小于号(.. <)。 半开表示范围是从0到但不包括5。即数字(0、1、2、3、4)。
开放和半开放范围必须始终增加。 换句话说,第二个数字必须始终大于或等于第一个。 可数范围通常用于循环和switch语句,这意味着在本章的其余部分中,你还将使用范围!
随机插曲
编程中的一个普遍需求是能够生成随机数。 Swift提供了该语言内置的功能,非常方便!
例如,假设有一个应用需要模拟模具的滚动。 你可能需要做一些事情,直到六分。 既然你知道了while循环,就可以使用random功能
做到这一点。 你可以这样做:
1 | while Int.random(in: 1...6) != 6 { |
注意:这里的
random(in :)
是对函数的调用。 你将在第5文“函数”中详细了解这些内容,并在第12文“方法”中将其应用于类型。
For loops
在上一章中,你研究了while循环。 现在你已经了解了范围,是时候来看看另一种类型的循环:for循环。 这可能是最常见的循环,你将使用它运行代码一定次数。
你可以这样构建一个for循环:
1 | for <CONSTANT> in <COUNTABLE RANGE> { |
循环以for关键字开头,后跟为循环常数指定的名称(稍后会详细介绍),然后是in,然后是要循环通过的范围。 这是一个例子:
1 | let count = 10 |
在上面的代码中,for循环遍历范围1进行计数。 在第一次迭代中,我将等于范围内的第一个元素:1.每次循环,我都会递增直到等于count; 循环将执行最后一次,然后结束。
注意:如果你使用半开范围,则最后一次迭代将看到i等于count-1。
在循环内部,将i添加到sum变量; 它运行10次以计算序列1 + 2 + 3 + 4 + 5 + …一直到10。
以下是每次迭代的常数i和变量和的值:
- 迭代开始1:i = 1,sum = 0
- 迭代开始2:i = 2,sum = 1
- 迭代开始3:i = 3,sum = 3
- 迭代开始4:i = 4,sum = 6+ 迭代开始5:i = 5,sum = 10
- 迭代开始6:i = 6,sum = 15
- 迭代开始7:i = 7,sum = 21
- 迭代的开始8:i = 8,sum = 28
- 迭代开始9:i = 9,sum = 36
- 迭代10的开始:i = 10,总和= 45
- 迭代10之后:sum = 55
就范围而言,i常数仅在for循环的范围内可见,这意味着它在循环之外不可用。
注意:如果你数学上很精明,可能会注意到此示例计算的是三角形数。 快速说明:http://bbc.in/ 1O89TGP
Xcode的 “playground” 为你提供了可视化此类迭代的便捷方法。 将鼠标悬停在结果窗格中的总和+ = i线上,你会在右侧看到一个白点。 将鼠标悬停在该点上以显示加号(+)按钮:
单击此加号(+)按钮,Xcode将在playground代码编辑器中的线下显示一个图形:
此图使你可以在循环迭代时可视化sum变量。
最后,有时你只想循环一定次数,因此你不需要完全需要使用循环常数。
在这种情况下,你可以使用下划线表示你忽略它,如下所示:
1 | sum = 1 |
此代码不需要循环常量; 循环只需要运行一定次数。 在这种情况下,范围是0到(但不包括)count,并且是半开的。 这是编写运行一定次数的循环的常用方法。 也可以仅在特定条件下执行迭代。 例如,假设你想计算一个类似于三角数的和,但仅针对奇数:
1 | sum = 0 |
前一个循环在for循环语句中有一个where子句。 循环仍会遍历范围1内的所有值进行计数,但仅在where条件为true时才执行循环的代码块; 在这种情况下,我很奇怪。
继续并标记为语句
有时,你可能希望跳过特定情况下的循环迭代,而不会完全脱离循环。 你可以使用continue语句执行此操作,该语句立即结束循环的当前迭代并开始下一个迭代。
注意:在许多情况下,你可以使用刚学到的更简单的where子句。 continue语句为你提供了更高级别的控制,使你可以决定何时何地跳过迭代。
以8 x 8网格为例,其中每个单元格包含行的值乘以列。 乘法表看起来很多行,不是吗?
假设你要计算所有单元格的总和,但不包括所有偶数行,如下所示:
使用for循环,可以实现以下目的:
1 | sum = 0 |
当模2的行等于0时,该行是偶数。 在这种情况下,继续操作会使for循环跳到下一行。 就像break一样,continue适用于for循环和while循环。
第二个代码示例将计算所有单元格的总和,不包括那些列大于或等于行的单元格。
为了说明这一点,它应该汇总以下单元格:
使用for循环,可以实现以下目的:
1 | sum = 0 |
前面的代码块使用了标记的语句,将两个循环分别标记为rowLoop和columnLoop。 当行等于内部columnLoop内部的列时,外部rowLoop将继续。
你可以将带有此类标记的语句与break配合使用以突破特定循环。 通常,中断并继续最内层的循环工作,因此如果要操作外层循环,则需要使用带标签的语句。
Switch语句
你还可以通过switch语句控制流。 它根据变量或常量的值执行不同的代码。 这是一个作用于整数的switch语句:
1 | let number = 10 |
在此示例中,代码将打印以下内容:
1 | Non-zero |
该switch语句的目的是确定一个数字是否为零。 它将变得更加复杂-我保证!
要处理特定的情况,请使用情况,后跟要检查的值(在这种情况下为0)。然后,使用default表示所有其他值应发生的情况。
这是另一个示例:
1 | switch number { |
这次你检查10,在这种情况下,你将打印一条消息。 其他值不应该发生。 如果你不希望任何情况发生,请使用break语句。 这告诉Swift,你的意思是不要在此处编写任何代码,并且什么也不会发生。 案例永远不能为空,因此即使只是休息,你也必须编写一些代码!
当然,switch语句还可以使用整数以外的数据类型。 它们适用于任何数据类型!
这是打开字符串的示例:
1 | let string = "Dog" |
这将打印以下内容:
1 | Animal is a house pet. |
在此示例中,你为案例提供了两个值,这意味着如果该值等于“ Cat”或“ Dog”,则该语句将执行案例。
高级switch语句
你还可以为switch语句提供不止一种情况。 在上一章中,你看到了一个if语句,该语句使用多个else子句将一天中的一个小时转换为描述一天中该部分的字符串。 你可以使用switch语句更简洁地重写它,如下所示:
1 | let hourOfDay = 12 |
此代码将打印以下内容:
1 | Afternoon |
还记得范围吗? 好了,你可以使用范围来简化此switch语句。 你可以使用范围重写以上代码:
1 | switch hourOfDay { |
这比在所有情况下单独写出每个值更简洁。
如果存在多个案例,该语句将执行第一个匹配的案例。 你可能会同意,此示例比使用if语句更为简洁明了。
同样,它也略为精确,因为if语句方法未解决负数,此处正确地将其视为无效。
也可以根据值的属性将个案与条件匹配。 如你在第2章“类型和操作”中所了解的那样,你可以使用模运算符来确定整数是偶数还是奇数。
考虑以下代码:
1 | switch number { |
这将打印以下内容:
1 | Even |
该switch语句使用let-where语法,这意味着仅当某个条件为true时,大小写才匹配。 let部分将值绑定到名称,而where部分提供布尔条件,该条件必须为true才能匹配大小写。
在此示例中,你设计了大小写匹配的情况,如果值是偶数(即模2的值等于0)。
根据条件匹配值的方法称为模式匹配。
在前面的示例中,绑定引入了不必要的常数x; 它只是数字的别称。
你可以在where子句中使用数字,并用下划线替换绑定以忽略它。
1 | switch number { |
部分匹配
可以使用具有匹配效果的switch语句的另一种方法如下:
1 | let coordinates = (x: 3, y: 2, z: 5) |
该switch语句使用部分匹配。 以下是每种情况的工作顺序:
- 1.精确匹配值是(0,0,0)的情况。 这就是3D空间的起源。
- 2.匹配y = 0,z = 0和x的任何值。 这意味着坐标在x轴上。
- 3.匹配x = 0,z = 0和y的任何值。 这意味着坐标在y轴上。
- 4.匹配x = 0,y = 0和z的任何值。 这意味着坐标在z轴上。
- 5.匹配其余坐标。
你使用下划线表示你不在乎价值。 如果你不想忽略该值,则可以将其绑定并在switch语句中使用它。
这是如何执行此操作的示例:
1 | switch coordinates { |
在这里,轴案例使用let语法提取相关值。 然后,代码使用字符串插值来打印值以构建字符串。
请注意,你在此switch语句中不需要默认值。 这是因为最后一种情况实质上是默认情况; 它匹配任何东西,因为元组的任何部分都没有约束。 如果switch语句将所有可能的值及其大小写用尽,则不需要默认值。
还要注意如何使用单个let绑定元组的所有值:let(x,y,z)与(let x,let y,let z)相同。
最后,你可以使用之前看到的相同的让位语法来匹配更复杂的情况。 例如:
1 | switch coordinates { |
在这里,你匹配了“ y等于x”和“ y等于x平方”的线。 这些就是switch语句的基础!
关键点
- 你可以使用可数范围来创建整数序列,并递增以从一个值移至另一个值。
- 封闭范围包括起始值和结束值。
- 半开范围包括起始值,并在结束值前停一档。
- For循环可让你遍历一个范围。
- continue语句使你可以完成循环的当前迭代并开始下一个迭代。
- 带标签的语句使你可以使用break并在外部循环上继续。
- 你可以使用switch语句来确定要运行的代码,具体取决于变量或常数。
- switch语句的功能来自利用模式匹配来使用复杂规则比较值。