在上一個章節,已經有使用到 if
來終止迴圈的執行,透過條件的約束來去執行不同的程式碼區段,這種方式就是流程控制的一環,Swift 有兩個方式,可以用來做到這件事:If
以及 Switch
,If 通常用於簡單的條件判斷,Switch 搭配著 Case 可用來判斷多種不同的條件,有別於其他程式的 Switch
,在 Swift 中又是一個強大的功能,到底有多強大,讓我們繼續看下去。
If 條件判斷句,用來判斷某個特定條件,若符合條件的話就執行 {}
內的程式碼。
if 條件 {
// 如果為真 ...
}
這邊有個簡單的範例,今天有個常數叫做號碼,並給定初始值為 5
,下面的判斷式表示:假使號碼是 5
的話,就印出 "現在號碼是五號"
。
let 號碼 = 5
if 號碼 == 5 {
print("現在號碼是五號")
}
// Prints: 現在號碼是五號
所以號碼只要不是 5 就不會印出 現在號碼是五號
。
let 號碼 = 4
if 號碼 == 5 {
print("現在號碼是五號")
}
// 因為 4 不等於 5,所以就不會進入條件為真的程式碼中,自然就不會印出什麼東西。
還記得我們之前在《 Day 7 | Swift 基本運算子 》那篇提到的邏輯運算子嗎?我們也可以使用邏輯運算子來判斷多個條件:
if (isRain) && (noUmbrella || noRainCoat) {
print("我是落湯雞")
}
如果現在正在下雨,而且又沒有雨傘或是雨衣,就會被淋成落湯雞。
上面的例子的話他只有判斷條件為真的情況,但假如我們想要在不符合條件的時候,執行另外一個程式區段,我們可以使用 else { ... }
。
if 條件 {
// 如果為真的話...
} else {
// 否則 ...
}
if 老婆生氣了 {
print("罰跪,今晚睡沙發")
} else {
print("今晚睡床")
}
來解釋一下上面的語句:如果老婆生氣了,今晚就要睡沙發,否則老婆沒生氣,今晚就可以睡床上了,只要不符合就執行 else
那段程式碼。
再來看另外一個例子,按照上述的方式,只會有兩種選擇,假定我們想要再做多一點判斷,那我們可以使用 else if { ... }
來約束更多條件。
if 條件1 {
// 如果 條件1 為真
} else if 條件2 {
// 如果 條件2 為真
} else {
// 否則 ...
}
來看看實際的範例:
let 分數 = 87
if 分數 == 100 {
print("A+")
} else if 分數 >= 90 {
print("A")
} else if 分數 >= 80 {
print("B")
} else {
print("C")
}
// Prints: B
在執行多個條件判斷時,會由上而下依序判斷,所以上面這個範例,分數為 87
分,一開始不符合 分數 == 100
,於是乎往下判斷 分數 >= 90
,也不符合,再繼續往下判斷 分數 >= 80
,結果為真,所以就會印出 B
,至於已經找到符合的條件了,這時候就不會再繼續往下判斷,則會跳出整個判斷式,自然就不會走到 else
了。
這個 Switch 不是 Nintendo Switch。
先來看一下 Switch 的使用方式:
switch element {
case 數值1:
// 如果 element 是 數值1 ...
case 數值2:
// 如果 element 是 數值2 ...
case 數值3, 數值4:
// 如果 element 是 數值3 或是 數值4 ...
default:
// 否則 ...
}
我們以 switch
開頭,將一個 element 當做要被判斷的元素,這個 element
可以是某個變數或是常數,甚至是某個資料的特定屬性,我們假設這個資料會有數個情況,然而這些情況都是以 case
為開頭,後方加入與 element 同型別的數值,每一個 case 就等同於 If 條件判斷句中獨立的條件狀況,最後 default
就像是 else
如果 element 都不符合上述的 case
就執行 default
,來看下方的範例:
let 等第 = "B"
switch 等第 {
case "A++":
print("卓越")
case "A":
print("品學兼優")
case "B", "C":
print("還有很多進步空間")
default:
print("沒救,請離開")
}
// Prints: 還有很多進步空間
有個常數等第
,給定初始值為 "B"
,我們用 Switch 的方式來判斷,一樣由上而下,依序判斷,因為都不符合前面的數值直到 case "B", "C"
才符合條件,印出 還有很多進步空間
。
這邊的 case 判斷是跟其他的不太一樣,有兩個數值,這代表著:如果符合這兩個其中一個,條件就成立,所以如果等第為 "C"
,一樣會印出 還有很多進步空間
。
但假使都不符合任何一個 case 條件,會執行 default
的程式碼,就會印出 沒救,請離開
。
let 等第 = "E"
switch 等第 {
case "A++":
print("卓越")
case "A":
print("品學兼優")
case "B", "C":
print("還有很多進步空間")
default:
print("沒救,請離開")
}
// Prints: 沒救,請離開
但是我們有辦法用 Switch-Case
的方式來處理像是上面範例 分數 >= 90
,這種條件嗎?
這裡就要介紹 Switch-Case
強大的地方,case 允許輸入 Range
來當作判斷的數值,來看一下範例:
let 分數 = 87
switch 分數 {
case 100:
print("A+")
case 90..<100:
print("A")
case 80..<90:
print("B")
default:
print("C")
}
// Prints: B
可以使用 Range 的方式來當作 case 的條件判斷,這麼一來就比較清楚知道,假定分數落在什麼區間,就會執行哪一段程式。
除了可以使用 Range 當作 case,也可以使用 Tuple,這邊有個範例,假定有個以 X 軸和 Y 軸範圍是 (-2...2, -2...2)
的平面圖,可以使用 Tuple 的方式來判斷不同 case:
let 座標 = (1, 1)
switch 座標 {
case (0, 0):
print("在中心點")
case (_, 0):
print("在 X 軸上")
case (0, _):
print("在 Y 軸上")
case (-2...2, -2...2):
print("在範圍內")
default:
print("超出範圍了!")
}
// Prints: 在範圍內
來解釋一下這上面的 case,我們可以 Tuple 且是具有相同型別的數值來當作比對的標準,比如可以判斷 case 是否為 (0, 0)
,但是你也可以使用 _
忽略其中一個數值,只需要確定 X 軸或是 Y 軸為 0
,甚至是你可以在 Tuple 裡面使用 Range,來判斷座標是否落在範圍內。
除了以 Tuple 的形式來表達 case 之外,還有一個功能就是,你可以宣告一個臨時常數來傳遞及使用:
let 座標 = (1, 1)
switch 座標 {
case (let x, 0):
print("在 X 軸上,座標為 (\(x), 0)")
case (0, let y):
print("在 Y 軸上,座標為 (0, \(y))")
case let (x, y):
print("座標為 (\(x), \(y))")
}
// Prints: 座標為 (1, 1)
我們宣告了臨時常數,除了判斷條件之外,還可以拿來存取。
最後就是 Switch-Case
最強大的地方,你可以使用相同的 case 條件,加上 Where 子句,來檢查其他的條件,我們繼續用上面的範例來解釋:
let 座標 = (1, 1)
switch 座標 {
case let (x, y) where x == y:
print("座標為 (\(x), \(y)),且為正斜率")
case let (x, y) where x == -y:
print("座標為 (\(x), \(y)),且為負斜率")
case let (x, y):
print("座標為 (\(x), \(y))")
}
// Prints: 座標為 (1, 1),且為正斜率
這個範例用來判斷是否為在哪條線上,像這種用法如果以 If 條件判斷式來表示就會很複雜,但是 Switch-Case
卻可以做到,而且也易讀,好理解。
這句話是什麼意思?exhaustive 中文意思是詳盡的、全面的,代表如果要被拿來判斷的 element 具有明確的範圍時,在使用 Switch-Case
就必須考慮到每個情況,這邊用 Enum 來舉個例子( Enum 可用把多個相關的數值集合起來當作一種型別 ):
enum Animals {
case dog
case cat
case bird
}
let animals: Animals = Animals.dog
switch animals {
case .dog:
print("這是狗")
case .cat:
print("這是貓")
case .bird:
print("這是鳥")
}
假定今天已經很明確知道,Animals
就是只有三種動物,那麼在使用 Switch-Case
就不能少判斷任何一種情況,否則就是要使用 default
作為最後判斷條件,要不然就會跳出 Switch must be exhaustive
的錯誤訊息。
但是奇怪的是我們在上述的可以在 Tuple 中宣告臨時常數的範例中,為什麼 Switch-Case
可以不用加上 default
?
因為
let (x, y)
就可以代表其他任何值,像是 (100, 2)、(-12, 3),因為他沒有特別聲明特定的值,所以這種方式即可考慮到所有可能的情況,所以就無需使用default
作為最後的判斷條件。
在 C 以及 Objective-C 中使用 Switch 的話,如果不加上 break
,他會繼續判斷接下來的 case,然而在 Switch 中只要找到第一個符合的 case,就會中斷,但是如果你想要在 case 中加入 break
也是可以的喔。