檢查條件是否成立,不成立就離開的 guard else

guard else 的語法和作用和 if else 很像,但卻有一些不同的地方,讓我們透過以下的 function motherSay 說明。

guard else 語法說明

func motherSay(age: Int) {
guard age > 18 else {
print("18 歲以下要乖乖唸書")
return
}
print("18 歲以上,可以盡情談戀愛")
}

guard 跟 if 一樣,後面都是接結果為 true 或 false 的條件,但 guard 卻有以下幾點不同之處:

  • guard 喜歡依賴別人,不能沒有 else。
在輸入程式時,只要記得搭配 Xcode 的自動完成,選擇選單裡的 guard — Swift Guard Statement,Xcode 將幫我們自動補上 else。
  • guard 後專門描述我們希望成立的條件。當條件成立時,程式將離開 guard 搭配的 else { },繼續往下執行我們希望條件成立時做的事。
  • 當 guard 的條件不成立時,將執行 else { } 的程式。
  • else { } 的程式執行後,必須離開 guard 所在區塊,如此才不會繼續往下執行條件成立時要做的事。就像剛剛的例子,我們利用 return 離開 function motherSay。
else 的 { } 裡忘了加 return 離開,因此產生紅色錯誤

因此剛剛的 function motherSay,我們在 guard 之後描述談戀愛須滿足的必要條件,age 必須大於 18 。

當 age 超過 18 時,將印出 18 歲以上,可以盡情談戀愛

motherSay(age: 25)

當 age 小於 18 時,將執行 else { } 的程式,印出 18 歲以下要乖乖唸書

motherSay(age: 10)

guard else { } 裡除了搭配 return,有時也可以搭配 break,continue 或 throw,只要能讓它不會繼續往下執行條件成立時要做的事 ,比方以下寫在 for 裡的 guard 例子。

搭配 break

func motherSay(ages: [Int]) {
for age in ages {
guard age > 18 else {
print("18 歲以下要乖乖唸書")
break
}
print("18 歲以上,可以盡情談戀愛")
}
}

motherSay(ages: [25, 10, 20])

搭配 continue

func motherSay(ages: [Int]) {
for age in ages {
guard age > 18 else {
print("18 歲以下要乖乖唸書")
continue
}
print("18 歲以上,可以盡情談戀愛")
}
}

motherSay(ages: [25, 10, 20])

由於 guard else 和 if else 十分相像,所以 guard else 也可以搭配多重條件,例如以下例子:

年紀 > 18 並且體重超過 40,才能談戀愛

func motherSay(age: Int, weight: Int) {
guard age > 18, weight > 40 else {
print("年紀不夠大,體重太輕,只能乖乖唸書")
return
}
print("夠成熟夠穩重,可以盡情談戀愛")
}

年紀 > 18,或存款超過 10000 即可談戀愛

func motherSay(age: Int, money: Int) {
guard age > 18 || money > 10000 else {
print("年紀不夠大,或是錢太少,只能乖乖唸書")
return
}
print("夠成或夠有錢熟,可以盡情談戀愛")
}

guard else 語法的優點

看來 guard else 的功能似乎跟 if else 大同小異,為什麼 Swift 還要多此一舉,發明 guard else 呢?在某些情況,guard else 的寫法比 if else 更好,它將帶來以下幾點好處:

  • 程式的意思更清楚,可讀性更好。

guard 後面描述我們希望成立的條件,比方對象的年紀條件在 18 ~ 30 歲之間,所以程式的意思會更清楚,不像 if 後面可能描述我們希望成立的條件,也可能描述我們希望不成立的條件。

  • 實現提早離開(early exit)的效果,不會浪費時間執行用不到的程式。

在 App 的表單輸入頁面,guard 很適合用來檢查欄位。比方我們做了一個通訊錄 App, 在新增聯絡人時,程式須做許多檢查,像是名字是否忘了輸入,email 格式是否有錯等。確認每個欄位都 ok 後,才能完成新增聯絡人的動作,若有某個欄位出錯,應該跳出錯誤提醒使用者。

因此,如果發現名字有問題,應該不要再浪費時間執行接下來的程式,而 guard 正是幫我們實現此功能的好幫手。假設新增聯絡人的欄位有十個,我們可用十個 guard 檢查,一旦某個 guard 出錯即顯示錯誤,不再往下執行。唯有通過十個 guard 的層層考驗,才會執行最後新增聯絡人的動作。

func addContact(name: String, age: Int) {
guard name.isEmpty == false else {
print("請輸入名字")
return
}
guard age >= 1 else {
print("未滿 1 歲,不夠格當朋友")
return
}
// 以下區塊可加入新增聯絡人的程式碼
print("新增聯絡人")
}

addContact(name: "彼得潘", age: 20)

若將剛剛的 function addContact 改用 if else 的寫法,將如下圖所示,很難一眼看出新增聯絡人的程式寫在哪。相反的,guard 的寫法將十分清楚,一眼就能看出它落在通過重重 guard 考驗後的段落。

func addContact(name: String, age: Int) {
if name.isEmpty {
print("請輸入名字")
} else {
if age < 1 {
print("未滿 1 歲,不夠格當朋友")
} else {
// 以下區塊可加入新增聯絡人的程式碼
print("新增聯絡人")
}
}
}

除了基本的 guard else,guard 也常跟 let 搭配,組成檢查 optional 是否有值的 guard let 語法,相關說明可參考以下連結。

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com