控制流
什么是控制流?
所謂控制流,是用來控制一件事物的流程的。跟數(shù)據(jù)類型一樣,同樣是模擬我們大腦對現(xiàn)實生活的處理模式。
還記得我在開始舉的例子的嗎?一起來回顧一下:
早晨起(床),吃完(早餐),出門穿上(外套),花(兩元錢)買了公交(車票),到公司開始(干活)。
我們的大腦能夠輕松處理不同的數(shù)據(jù)類型,并且,我們實際上還在處理流程控制。讓我們將上面這個例子細(xì)分一下:
- 當(dāng)我吃早飯時,只要沒吃完,我就會一直吃,直到吃完或者吃飽;
- 出門的時候檢查有沒有穿外套,穿了外套再出門;
- 等公交車時,一輛接一輛,到了我要等的22路公交車,我就上車。
- 如果我趕上了公交車,我就會到公司干活;
看吧,這里隱藏了相當(dāng)多的條件或循環(huán)。只有通過這種流程控制,我們才能自由處理各個對象。我們的大腦相當(dāng)強大,強大到你根本不需要費勁思考,這些事情就順理成章的完成了。
再說回可憐的計算機,它需要你給他交待具體的任務(wù)安排。就像家長給上小學(xué)的孩子輔導(dǎo)作業(yè)一樣,你需要把自己的認(rèn)知也暫時拉低到小學(xué)水平,這樣你才能給孩子講明白題目。
有哪些控制流?
明白了什么是控制流,我們再來看看,Swift能接受哪些具體的命令來組織事務(wù)的控制流程:
-
for-in循環(huán):多用在數(shù)據(jù)組合中,對單個數(shù)據(jù)進行逐項遍歷; -
While循環(huán):如果某個條件滿足,就一直循環(huán),直到條件不滿足; -
if條件語句:如果某個條件滿足,就做某件事,否則就做另一件事; -
Switch匹配語句:列舉很多條件,滿足其中某個條件時,做某件事。
上面,只是簡略的闡述了每個語句的意思,實際運用時,有很多細(xì)節(jié)需要注意,我們逐條來看一下。
1. for-in 循環(huán)
for-in循環(huán)有點像是做上樓梯(每個臺階踩一遍),點名(每個人都要點一遍)這種比較機械的工作。
- 基本用法
for-in循環(huán)我們之前已經(jīng)多次用過了,在遍歷數(shù)組,集合,字典中的值時,經(jīng)常用到。
var arrayNumbers = [1,2,3]
for i in arrayNumbers {
print(i)
}
// 1,2,3
- 遍歷區(qū)間
我們之前提到過區(qū)間,比如1...6,就是1,2,3,4,5,6這幾個數(shù)字,也是可以用for in進行遍歷的。
for i in 1...6 {
print(i)
}
// 1,2,3,4,5,6
在這個例子中,i是1-6范圍的值,每一步都取了一次當(dāng)前值,并打印出來。
我們還可以僅僅執(zhí)行這段循環(huán),而不打印出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中試一下結(jié)果。
這段代碼實現(xiàn)了更加多的參數(shù),在100這個范圍內(nèi),從2開始數(shù),每隔5數(shù)一次。
2. While 循環(huán)
while condition {
statements
}
如果說for in做的工作比較機械的話,while,if,switch就比較有目的性了,我們先看while。
- 基本用法
首先看一個示例,我會持續(xù)吃,直到我感覺有差不多八成飽。這段描述可以用代碼來表達:
var 飽腹感 = 1
while 飽腹感 < 8 {
print("再吃一口……")
飽腹感 += 1
}
分析這段代碼:
首先,我很餓,用變量表示var 飽腹感 = 1,我給自己設(shè)定的條件是要吃到八成飽,飽腹感 < 8這實際上是一個判斷,得出的就是一個判斷值,也就是布爾值,是true or false。
開始飽腹感是1,滿足了飽腹感 < 8這個判斷,就會執(zhí)行while包起來的語句,我會再吃一口,飽腹感就會加1。這時,代碼運行完了,再從頭運行,再次判斷飽腹感的值,直到飽腹感=8的時候,條件就不滿足了,就停止執(zhí)行。
代碼停止了,但是代碼運行了7次再吃一口,也達到了目的。
類比:
for-in也能實現(xiàn)類似的多次執(zhí)行的效果,但是while更接近自然語言,可以類比中文當(dāng)……時,就……。在合適的情況下使用,代碼的可讀性就會更好。
這有點像上學(xué)的時候,老師給我們批改作文,會說你這里用詞不當(dāng)。怎么才能用詞恰當(dāng)呢?就需要多讀,多寫,慢慢進步。等到你成年后,你就不太會說:我已經(jīng)飽的無與倫比了,這樣用詞不當(dāng)?shù)脑捔恕?/p>repeat-while
repeat {
statements
} while condition
理解了while的基本用法后,這里就很好理解。repeat-while與while的最大區(qū)別就是,無論什么條件,先執(zhí)行一段代碼。用我們的例子說明,就是管他餓不餓,先吃一口。上面的代碼可以改為:
var 飽腹感 = 8
repeat {
print("再吃一口……")
飽腹感 += 1
}
while 飽腹感 < 8
這里,我把飽腹感的初始值設(shè)為8,雖然達到我的八成飽要求了,可是還要首先吃一口再說。
3. if 條件語句
if條件語句的意思是如果……就……,如果某個條件滿足,就執(zhí)行某個動作。一個蘿卜一個坑,對預(yù)期控制的比較精確,也是編程語言中最常用的邏輯控制語句。
- 基本用法
if condition {
statements
}
condition同樣是一個布爾值,statements是某個動作。
舉個與生活相關(guān)的例子,如果天氣晴朗,我就出門,用代碼可以表示:
var 天氣 = "晴朗"
if 天氣 == "晴朗" {
print("我要出門")
}
聲明一下,為了便于理解,我們使用了中文名稱作為變量,swift也能正常執(zhí)行,但是在正式開發(fā)中,盡量避免這樣使用。我能想到的最大缺點就是,這樣做會影響兼容性,因為其他大部分人都不這么干。
上面這段代碼,if的條件是成立的,因此會執(zhí)行print()語句,如果你把天氣的值改為其他,print()就不會執(zhí)行了。
- if else
既然是假設(shè),那么我們還會有更復(fù)雜的情況,比如,如果天氣晴朗,我就出門。如果陰天、下雨、大風(fēng)等壞天氣,我就在家上網(wǎng)。這段描述,可以用代碼表示如下:
var 天氣 = "下雨"
if 天氣 == "晴朗" {
print("我要出門")
} else {
print("在家上網(wǎng)")
}
這里,加了else的意思是,除了天氣 == "晴朗"這個條件,其他任何情況下,執(zhí)行的動作。
滿足一個條件,執(zhí)行一個命令。如果不滿足這個條件,就執(zhí)行另一個命令。
- if else if else
如果有多項判斷,可以使用else if。在上面的例子中,我們可以細(xì)化對不同情況的反應(yīng)。比如,如果天氣晴朗,我就出門;如果下雨,我就帶傘出門;否則,我就在家上網(wǎng)。
var 天氣 = "下雨"
if 天氣 == "晴朗" {
print("我要出門")
} else if 天氣 == "下雨" {
print("帶傘出門")
} else {
print("在家上網(wǎng)")
}
還有一種跟if條件很類似的 guard語句,主要在函數(shù)中使用,我們后面再說。
4. Switch 匹配語句
- 基本用法
如果有多項條件,每個條件都各自對應(yīng)一種動作時,除了用多個else if之外,還可以使用switch語句。
var 天氣 = "晴朗"
switch 天氣 {
case "晴朗":
print("出門遛彎。")
case "下雨":
print("出門帶傘。")
default:
print("在家上網(wǎng)。")
}
有沒有發(fā)現(xiàn)switch和if的最大區(qū)別?if后面的條件是布爾值,而switch后面是具體的數(shù)據(jù),case后面的值也是從具體的數(shù)據(jù)中做選擇。這樣就靈活了很多。
但是要注意,case是順序執(zhí)行,一旦滿足,后面就不再執(zhí)行了。
- 復(fù)合匹配
因此,我們可以輕松使用復(fù)合數(shù)據(jù)進行匹配
var 天氣 = "陰天"
switch 天氣 {
case "晴朗", "陰天":
print("出門遛彎。")
case "下雨":
print("出門帶傘。")
default:
print("在家上網(wǎng)。")
}
我在第一行case中同時列舉了兩個條件,陰天也能出門遛彎。如果是用if,你需要這樣列舉天氣=="晴朗" || 天氣=="陰天",因為if后面只能跟布爾值。
- 區(qū)間匹配
非布爾值帶來的好處,還可以使用區(qū)間。舉個另外的我們經(jīng)常用的評分例子:
var 分?jǐn)?shù) = 86
switch 分?jǐn)?shù) {
case 0...60:
print("不及格")
case 61...80:
print("良好")
case 81...100:
print("優(yōu)秀")
default:
print("分?jǐn)?shù)有誤")
}
- 元組匹配
switch還能按元組匹配,也很使用,看下面這個例子:
var 生命 = 90
var 魔法 = 86
switch (生命, 魔法) {
case (100, 100):
print("英雄的狀態(tài)完美!")
case (_, 30...100):
print("可以釋放魔法!")
case (0..<30, _):
print("生命值低,危險!")
default:
print("分?jǐn)?shù)有誤")
}
從這個例子,可以看到元組匹配的特性:能按元組精確匹配,使用_可以忽略某項匹配,可以按區(qū)間匹配。
- 值綁定
我們可以在case分支中,用常量或變量綁定條件中的值,這樣,方便在該分支中,繼續(xù)操作數(shù)據(jù)。
var status = (30,60)
switch status {
case let (生命, 魔法):
print("生命值:\(生命), 魔法值:\(魔法)")
let 狀態(tài)值 = 生命 + 魔法
print("\(狀態(tài)值)")
}
還可以配合where, 進行條件判斷。會讓綁定值顯得更有意義。
var status = (30,60)
switch status {
case let (生命, 魔法) where 生命 + 魔法 > 100:
print("可以釋放魔法!")
case let (生命, 魔法):
print("生命值:\(生命), 魔法值:\(魔法)")
let 狀態(tài)值 = 生命 + 魔法
print("狀態(tài)值(\(狀態(tài)值))不夠,不能釋放魔法。")
}
調(diào)整狀態(tài)值,能得到不同case執(zhí)行動作,你可以在Playground中多試試。
7. 控制轉(zhuǎn)移語句
最后,我們來簡單介紹幾條控制語句.
continue,break,fallthrough,return,throw
return多用在函數(shù)中,throw多用在錯誤處理中,我們也放在后面介紹。
continue,break,fallthrough這幾個語句主要用在前面所說的各種循環(huán)語句中,因為有時候這些循環(huán)的默認(rèn)執(zhí)行狀態(tài)并不能滿足需求,這時候,可以搭配這些語句,來控制流程的走向。
下面只是舉了部分例子,先想象結(jié)果如何,然后在Playground中驗證試試,也可以按自己的想法修改、調(diào)試:
continue
var 天氣 = ["晴朗","雷暴","陰天","下雨"]
for i in 天氣 {
if i == "雷暴" {
continue
} else {
print("\(i)可以出門")
}
}
在遍歷循環(huán)的時候,如果遇到“雷暴”,用continue跳過,不做任何事情。
break
var 天氣 = ["晴朗","陰天","下雨","雷暴","臺風(fēng)"]
for i in 天氣 {
if i == "雷暴" {
break
} else {
print("\(i)可以出門")
}
}
在遍歷的過程中,遇到“雷暴”,整條循環(huán)就停止了,后面就不會繼續(xù)判斷了。
fallthrough
var 天氣 = ["晴朗","陰天","下雨","雷暴","臺風(fēng)"]
for i in 天氣 {
switch i {
case "晴朗":
print("可以出門")
case "陰天":
// print("可以出門")
fallthrough
case "下雨":
print("帶傘出門")
default:
print("在家上網(wǎng)!")
}
}
在本段代碼中,fallthrough使本段代碼直接交給下一條case處理。使得“陰天”這條case也會打印“帶傘出門?!?/p>
小結(jié)與預(yù)告
掌握了流程控制,我們就可以對數(shù)據(jù)進行操控了。編程的本質(zhì),無非是一系列的假設(shè),判斷,循環(huán)等等。
我們可以利用已經(jīng)學(xué)到的知識,寫很多東西了。比如,
- 根據(jù)圓的半徑,求圓面積;
- 已知一個班10個同學(xué)的成績,根據(jù)他們的分?jǐn)?shù)進行不及格,良,優(yōu)的評級;
- 已知一位英雄的生命值和魔法值,每釋放一次魔法,就消耗10點生命和60點魔法,直到某一個值不能滿足最低的安全值。
這是三個例子,證明你根據(jù)已有知識,是能夠?qū)懗鲞@樣的程序的,哪怕簡單一些。
這也是三個作業(yè),沒有標(biāo)準(zhǔn)答案,你試著獨立寫一寫,對我們學(xué)習(xí)下一節(jié)很有幫助。
來點小提示:
- 算術(shù)運算符處理數(shù)字
- if或switch判斷分?jǐn)?shù)的范圍
- 用while循環(huán)包住一個if判斷,在其中進行變量的增減操作