iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 14
0
Software Development

給我 30 天,給你一輩子:Swift 從零開始系列 第 14

Day 14 | Swift 流程控制:If 和 Switch

  • 分享至 

  • xImage
  •  

Control Flow:Conditional Statement

在上一個章節,已經有使用到 if 來終止迴圈的執行,透過條件的約束來去執行不同的程式碼區段,這種方式就是流程控制的一環,Swift 有兩個方式,可以用來做到這件事:If 以及 Switch,If 通常用於簡單的條件判斷,Switch 搭配著 Case 可用來判斷多種不同的條件,有別於其他程式的 Switch ,在 Swift 中又是一個強大的功能,到底有多強大,讓我們繼續看下去。


If

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("我是落湯雞")
}

如果現在正在下雨,而且又沒有雨傘或是雨衣,就會被淋成落湯雞。

If-else

上面的例子的話他只有判斷條件為真的情況,但假如我們想要在不符合條件的時候,執行另外一個程式區段,我們可以使用 else { ... }

if 條件 {
	// 如果為真的話...
} else {
	// 否則 ...
}
if 老婆生氣了 {
    print("罰跪,今晚睡沙發")
} else {
	print("今晚睡床")
}

來解釋一下上面的語句:如果老婆生氣了,今晚就要睡沙發,否則老婆沒生氣,今晚就可以睡床上了,只要不符合就執行 else 那段程式碼。

If-else if

再來看另外一個例子,按照上述的方式,只會有兩種選擇,假定我們想要再做多一點判斷,那我們可以使用 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

這個 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: 沒救,請離開

Case 的型態:Range

但是我們有辦法用 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 的條件判斷,這麼一來就比較清楚知道,假定分數落在什麼區間,就會執行哪一段程式。

Case 的型態:Tuple

除了可以使用 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,來判斷座標是否落在範圍內。

Case 的型態:Tuple + Constant

除了以 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)

我們宣告了臨時常數,除了判斷條件之外,還可以拿來存取。

Case 的型態:Tuple + Constant + Where

最後就是 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 卻可以做到,而且也易讀,好理解。

冷知識 1:Switch 的使用必須是 exhaustive

這句話是什麼意思?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 的錯誤訊息。

https://ithelp.ithome.com.tw/upload/images/20200914/20118283NmAu6JPvTz.png

但是奇怪的是我們在上述的可以在 Tuple 中宣告臨時常數的範例中,為什麼 Switch-Case 可以不用加上 default

因為 let (x, y) 就可以代表其他任何值,像是 (100, 2)、(-12, 3),因為他沒有特別聲明特定的值,所以這種方式即可考慮到所有可能的情況,所以就無需使用 default 作為最後的判斷條件。

冷知識 2:Swift 中的 Switch 不需加上 break 跳出

在 C 以及 Objective-C 中使用 Switch 的話,如果不加上 break,他會繼續判斷接下來的 case,然而在 Switch 中只要找到第一個符合的 case,就會中斷,但是如果你想要在 case 中加入 break 也是可以的喔。


上一篇
Day 13 | Swift Loops 的糾葛終章:While 和 Repeat-While
下一篇
Day 15 | Swift 流程控制:Guard
系列文
給我 30 天,給你一輩子:Swift 從零開始30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言