Swift5-外行零基础入门_9-控制流

控制流

什么是控制流?

所谓控制流,是用来控制一件事物的流程的。跟数据类型一样,同样是模拟我们大脑对现实生活的处理模式。
还记得我在开始举的例子的吗?一起来回顾一下:

早晨起(床),吃完(早餐),出门穿上(外套),花(两元钱)买了公交(车票),到公司开始(干活)。

我们的大脑能够轻松处理不同的数据类型,并且,我们实际上还在处理流程控制。让我们将上面这个例子细分一下:

  • 当我吃早饭时,只要没吃完,我就会一直吃,直到吃完或者吃饱;
  • 出门的时候检查有没有穿外套,穿了外套再出门;
  • 等公交车时,一辆接一辆,到了我要等的22路公交车,我就上车。
  • 如果我赶上了公交车,我就会到公司干活;

看吧,这里隐藏了相当多的条件或循环。只有通过这种流程控制,我们才能自由处理各个对象。我们的大脑相当强大,强大到你根本不需要费劲思考,这些事情就顺理成章的完成了。
再说回可怜的计算机,它需要你给他交待具体的任务安排。就像家长给上小学的孩子辅导作业一样,你需要把自己的认知也暂时拉低到小学水平,这样你才能给孩子讲明白题目。

有哪些控制流?

明白了什么是控制流,我们再来看看,Swift能接受哪些具体的命令来组织事务的控制流程:

  • for-in 循环:多用在数据组合中,对单个数据进行逐项遍历;
  • While 循环:如果某个条件满足,就一直循环,直到条件不满足;
  • if 条件语句:如果某个条件满足,就做某件事,否则就做另一件事;
  • Switch 匹配语句:列举很多条件,满足其中某个条件时,做某件事。
    上面,只是简略的阐述了每个语句的意思,实际运用时,有很多细节需要注意,我们逐条来看一下。

1. for-in 循环

for-in循环有点像是做上楼梯(每个台阶踩一遍)点名(每个人都要点一遍)这种比较机械的工作。

  • 基本用法
    for-in循环我们之前已经多次用过了,在遍历数组,集合,字典中的值时,经常用到。
var arrayNumbers = [1,2,3]
for i in arrayNumbers {
    print(i)
}
// 1,2,3
  • 遍历区间
    我们之前提到过区间,比如1...6,就是1,2,3,4,5,6这几个数字,也是可以用for in进行遍历的。
for i in 1...6 {
    print(i)
}
// 1,2,3,4,5,6

在这个例子中,i是1-6范围的值,每一步都取了一次当前值,并打印出来。
我们还可以仅仅执行这段循环,而不打印出i

for i in 1...6 {
    print("Hello")
}
// 打印了六遍"Hello"

在这个例子中,我们并没有在后面使用i,因此,我们可以用_代替i

for _ in 1...6 {
    print("Hello")
}
// 同样打印了六遍"Hello"
  • 步进遍历
    上楼梯的时候,我可以两步两步上;也可以从二楼开始上(也许是坐电梯到的二楼?)。总之,有选择的可能。
    这时,我们可以使用stride(from:to:by:)或者是stride(from:through:by:),先看下面的例子:
for i in stride(from:2, to: 100, by: 5) {
    print(i)
}
// 请自己在Playground中试一下结果。

这段代码实现了更加多的参数,在100这个范围内,从2开始数,每隔5数一次。

2. While 循环

while condition {
    statements
}

如果说for in做的工作比较机械的话,while,if,switch就比较有目的性了,我们先看while

  • 基本用法
    首先看一个示例,我会持续吃,直到我感觉有差不多八成饱。这段描述可以用代码来表达:
var 饱腹感 = 1
while 饱腹感 < 8 {
    print("再吃一口……")
    饱腹感 += 1
}

分析这段代码:
首先,我很饿,用变量表示var 饱腹感 = 1,我给自己设定的条件是要吃到八成饱,饱腹感 < 8这实际上是一个判断,得出的就是一个判断值,也就是布尔值,是true or false
开始饱腹感是1,满足了饱腹感 < 8这个判断,就会执行while包起来的语句,我会再吃一口饱腹感就会加1。这时,代码运行完了,再从头运行,再次判断饱腹感的值,直到饱腹感=8的时候,条件就不满足了,就停止执行。
代码停止了,但是代码运行了7次再吃一口,也达到了目的。

  • 类比:
    for-in也能实现类似的多次执行的效果,但是while更接近自然语言,可以类比中文当……时,就……。在合适的情况下使用,代码的可读性就会更好。
    这有点像上学的时候,老师给我们批改作文,会说你这里用词不当。怎么才能用词恰当呢?就需要多读,多写,慢慢进步。等到你成年后,你就不太会说:我已经饱的无与伦比了,这样用词不当的话了。

  • repeat-while

repeat {
    statements
} while condition

理解了while的基本用法后,这里就很好理解。repeat-whilewhile的最大区别就是,无论什么条件,先执行一段代码。用我们的例子说明,就是管他饿不饿,先吃一口。上面的代码可以改为:

var 饱腹感 = 8
repeat {
    print("再吃一口……")
    饱腹感 += 1
}
while 饱腹感 < 8

这里,我把饱腹感的初始值设为8,虽然达到我的八成饱要求了,可是还要首先吃一口再说。

3. if 条件语句

if条件语句的意思是如果……就……,如果某个条件满足,就执行某个动作。一个萝卜一个坑,对预期控制的比较精确,也是编程语言中最常用的逻辑控制语句。

  • 基本用法
if condition {
    statements
}

condition同样是一个布尔值,statements是某个动作。
举个与生活相关的例子,如果天气晴朗,我就出门,用代码可以表示:

var 天气 = "晴朗"
if 天气 == "晴朗" {
    print("我要出门")
}

声明一下,为了便于理解,我们使用了中文名称作为变量,swift也能正常执行,但是在正式开发中,尽量避免这样使用。我能想到的最大缺点就是,这样做会影响兼容性,因为其他大部分人都不这么干。
上面这段代码,if的条件是成立的,因此会执行print()语句,如果你把天气的值改为其他,print()就不会执行了。

  • if else
    既然是假设,那么我们还会有更复杂的情况,比如,如果天气晴朗,我就出门。如果阴天、下雨、大风等坏天气,我就在家上网。这段描述,可以用代码表示如下:
var 天气 = "下雨"
if 天气 == "晴朗" {
    print("我要出门")
} else {
    print("在家上网")
}

这里,加了else的意思是,除了天气 == "晴朗"这个条件,其他任何情况下,执行的动作。
满足一个条件,执行一个命令。如果不满足这个条件,就执行另一个命令。

  • if else if else
    如果有多项判断,可以使用else if。在上面的例子中,我们可以细化对不同情况的反应。比如,如果天气晴朗,我就出门;如果下雨,我就带伞出门;否则,我就在家上网。
var 天气 = "下雨"
if 天气 == "晴朗" {
    print("我要出门")
} else if 天气 == "下雨" {
    print("带伞出门")
} else {
    print("在家上网")
}

还有一种跟if条件很类似的 guard语句,主要在函数中使用,我们后面再说。

4. Switch 匹配语句

  • 基本用法
    如果有多项条件,每个条件都各自对应一种动作时,除了用多个else if之外,还可以使用switch语句。
var 天气 = "晴朗"
switch 天气 {
case "晴朗":
    print("出门遛弯。")
case "下雨":
    print("出门带伞。")
default:
    print("在家上网。")
}

有没有发现switchif的最大区别?if后面的条件是布尔值,而switch后面是具体的数据,case后面的值也是从具体的数据中做选择。这样就灵活了很多。
但是要注意,case是顺序执行,一旦满足,后面就不再执行了。

  • 复合匹配
    因此,我们可以轻松使用复合数据进行匹配
var 天气 = "阴天"
switch 天气 {
case "晴朗", "阴天":
    print("出门遛弯。")
case "下雨":
    print("出门带伞。")
default:
    print("在家上网。")
}

我在第一行case中同时列举了两个条件,阴天也能出门遛弯。如果是用if,你需要这样列举天气=="晴朗" || 天气=="阴天",因为if后面只能跟布尔值。

  • 区间匹配
    非布尔值带来的好处,还可以使用区间。举个另外的我们经常用的评分例子:
var 分数 = 86
switch 分数 {
case 0...60:
    print("不及格")
case 61...80:
    print("良好")
case 81...100:
    print("优秀")
default:
    print("分数有误")
}
  • 元组匹配
    switch还能按元组匹配,也很使用,看下面这个例子:
var 生命 = 90
var 魔法 = 86

switch (生命, 魔法) {
case (100, 100):
    print("英雄的状态完美!")
case (_, 30...100):
    print("可以释放魔法!")
case (0..<30, _):
    print("生命值低,危险!")
default:
    print("分数有误")
}

从这个例子,可以看到元组匹配的特性:能按元组精确匹配,使用_可以忽略某项匹配,可以按区间匹配。

  • 值绑定
    我们可以在case分支中,用常量或变量绑定条件中的值,这样,方便在该分支中,继续操作数据。
var status = (30,60)
switch status {
case let (生命, 魔法):
    print("生命值:\(生命), 魔法值:\(魔法)")
    let 状态值 = 生命 + 魔法
    print("\(状态值)")
}

还可以配合where, 进行条件判断。会让绑定值显得更有意义。

var status = (30,60)
switch status {
case let (生命, 魔法) where 生命 + 魔法 > 100:
    print("可以释放魔法!")
case let (生命, 魔法):
    print("生命值:\(生命), 魔法值:\(魔法)")
    let 状态值 = 生命 + 魔法
    print("状态值(\(状态值))不够,不能释放魔法。")

}

调整状态值,能得到不同case执行动作,你可以在Playground中多试试。

7. 控制转移语句

最后,我们来简单介绍几条控制语句.
continuebreakfallthroughreturnthrow
return多用在函数中,throw多用在错误处理中,我们也放在后面介绍。
continuebreakfallthrough这几个语句主要用在前面所说的各种循环语句中,因为有时候这些循环的默认执行状态并不能满足需求,这时候,可以搭配这些语句,来控制流程的走向。
下面只是举了部分例子,先想象结果如何,然后在Playground中验证试试,也可以按自己的想法修改、调试:

  • continue
var 天气 = ["晴朗","雷暴","阴天","下雨"]
for i in 天气 {
    if i == "雷暴" {
        continue
    } else {
        print("\(i)可以出门")
    }
}

在遍历循环的时候,如果遇到“雷暴”,用continue跳过,不做任何事情。

  • break
var 天气 = ["晴朗","阴天","下雨","雷暴","台风"]
for i in 天气 {
    if i == "雷暴" {
        break
    } else {
        print("\(i)可以出门")
    }
}

在遍历的过程中,遇到“雷暴”,整条循环就停止了,后面就不会继续判断了。

  • fallthrough
var 天气 = ["晴朗","阴天","下雨","雷暴","台风"]
for i in 天气 {
    switch i {
    case "晴朗":
        print("可以出门")
    case "阴天":
//        print("可以出门")
        fallthrough
    case "下雨":
        print("带伞出门")
    default:
        print("在家上网!")
    }
}

在本段代码中,fallthrough使本段代码直接交给下一条case处理。使得“阴天”这条case也会打印“带伞出门。”

小结与预告

掌握了流程控制,我们就可以对数据进行操控了。编程的本质,无非是一系列的假设,判断,循环等等。
我们可以利用已经学到的知识,写很多东西了。比如,

  • 根据圆的半径,求圆面积;
  • 已知一个班10个同学的成绩,根据他们的分数进行不及格,良,优的评级;
  • 已知一位英雄的生命值和魔法值,每释放一次魔法,就消耗10点生命和60点魔法,直到某一个值不能满足最低的安全值。
    这是三个例子,证明你根据已有知识,是能够写出这样的程序的,哪怕简单一些。
    这也是三个作业,没有标准答案,你试着独立写一写,对我们学习下一节很有帮助。

来点小提示:

  1. 算术运算符处理数字
  2. if或switch判断分数的范围
  3. 用while循环包住一个if判断,在其中进行变量的增减操作

你可能感兴趣的:(Swift5-外行零基础入门_9-控制流)