swift——控制流

Swift 提供了類(lèi)似 C 語(yǔ)言的流程控制結(jié)構(gòu),包括可以多次執(zhí)行任務(wù)的forwhile循環(huán),基于特定條件選擇執(zhí)行不同代碼分支的if涌穆、guardswitch語(yǔ)句监徘,還有控制流程跳轉(zhuǎn)到其他代碼的breakcontinue語(yǔ)句。

除了 C 語(yǔ)言里面?zhèn)鹘y(tǒng)的 for 循環(huán)凛忿,Swift 還增加了for-in循環(huán),用來(lái)更簡(jiǎn)單地遍歷數(shù)組(array),字典(dictionary)盔夜,區(qū)間(range),字符串(string)和其他序列類(lèi)型。

Swift 的switch語(yǔ)句比 C 語(yǔ)言中更加強(qiáng)大喂链。在 C 語(yǔ)言中返十,如果某個(gè) case 不小心漏寫(xiě)了break,這個(gè) case 就會(huì)貫穿至下一個(gè) case椭微,Swift 無(wú)需寫(xiě)break洞坑,所以不會(huì)發(fā)生這種貫穿的情況。case 還可以匹配更多的類(lèi)型模式蝇率,包括區(qū)間匹配(range matching)迟杂,元組(tuple)和特定類(lèi)型的描述。switch的 case 語(yǔ)句中匹配的值可以是由 case 體內(nèi)部臨時(shí)的常量或者變量決定本慕,也可以由where分句描述更復(fù)雜的匹配條件排拷。

For 循環(huán)

Swift 提供兩種for循環(huán)形式以來(lái)按照指定的次數(shù)多次執(zhí)行一系列語(yǔ)句:

  • for-in循環(huán)對(duì)一個(gè)集合里面的每個(gè)元素執(zhí)行一系列語(yǔ)句。
  • for 循環(huán)锅尘,用來(lái)重復(fù)執(zhí)行一系列語(yǔ)句直到達(dá)成特定條件達(dá)成监氢,一般通過(guò)在每次循環(huán)完成后增加計(jì)數(shù)器的值來(lái)實(shí)現(xiàn)。

For-In

可以使用for-in循環(huán)來(lái)遍歷一個(gè)集合里面的所有元素藤违,例如由數(shù)字表示的區(qū)間浪腐、數(shù)組中的元素、字符串中的字符顿乒。

下面的例子用來(lái)輸出乘 5 乘法表前面一部分內(nèi)容:

for index in 1...5 {
    print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25

例子中用來(lái)進(jìn)行遍歷的元素是一組使用閉區(qū)間操作符(...)表示的從15的數(shù)字议街。index被賦值為閉區(qū)間中的第一個(gè)數(shù)字(1),然后循環(huán)中的語(yǔ)句被執(zhí)行一次璧榄。在本例中特漩,這個(gè)循環(huán)只包含一個(gè)語(yǔ)句,用來(lái)輸出當(dāng)前index值所對(duì)應(yīng)的乘 5 乘法表結(jié)果犹菱。該語(yǔ)句執(zhí)行后拾稳,index的值被更新為閉區(qū)間中的第二個(gè)數(shù)字(2),之后print(_:separator:terminator:)函數(shù)會(huì)再執(zhí)行一次腊脱。整個(gè)過(guò)程會(huì)進(jìn)行到閉區(qū)間結(jié)尾為止访得。

上面的例子中,index是一個(gè)每次循環(huán)遍歷開(kāi)始時(shí)被自動(dòng)賦值的常量陕凹。這種情況下悍抑,index在使用前不需要聲明,只需要將它包含在循環(huán)的聲明中杜耙,就可以對(duì)其進(jìn)行隱式聲明搜骡,而無(wú)需使用let關(guān)鍵字聲明。

如果你不需要知道區(qū)間序列內(nèi)每一項(xiàng)的值佑女,可以使用下劃線(_)替代變量名來(lái)忽略對(duì)值的訪問(wèn):

let base = 3
let power = 10
var answer = 1
for _ in 1...power {
    answer *= base
}
print("\(base) to the power of \(power) is \(answer)")
// 輸出 "3 to the power of 10 is 59049"

這個(gè)例子計(jì)算 base 這個(gè)數(shù)的 power 次冪(本例中记靡,是310次冪)谈竿,從130次冪)開(kāi)始做3的乘法, 進(jìn)行10次摸吠,使用110的閉區(qū)間循環(huán)空凸。這個(gè)計(jì)算并不需要知道每一次循環(huán)中計(jì)數(shù)器具體的值,只需要執(zhí)行了正確的循環(huán)次數(shù)即可寸痢。下劃線符號(hào)_(替代循環(huán)中的變量)能夠忽略具體的值呀洲,并且不提供循環(huán)遍歷時(shí)對(duì)值的訪問(wèn)。

使用for-in遍歷一個(gè)數(shù)組所有元素:

let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
    print("Hello, \(name)!")
}
// Hello, Anna!
// Hello, Alex!
// Hello, Brian!
// Hello, Jack!

也可以通過(guò)遍歷一個(gè)字典來(lái)訪問(wèn)它的鍵值對(duì)啼止。遍歷字典時(shí)道逗,字典的每項(xiàng)元素會(huì)以(key, value)元組的形式返回,可以在for-in循環(huán)中使用顯式的常量名稱(chēng)來(lái)解讀(key, value)元組献烦。下面的例子中滓窍,字典的鍵(key)解讀為常量animalName,字典的值會(huì)被解讀為常量legCount

let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
    print("\(animalName)s have \(legCount) legs")
}
// ants have 6 legs
// cats have 4 legs
// spiders have 8 legs

字典元素的遍歷順序和插入順序可能不同仿荆,字典的內(nèi)容在內(nèi)部是無(wú)序的贰您,所以遍歷元素時(shí)不能保證順序坏平。

For

除了for-in循環(huán)拢操,Swift 提供使用條件判斷和遞增方法的標(biāo)準(zhǔn) C 樣式for循環(huán):

for var index = 0; index < 3; ++index {
    print("index is \(index)")
}
// index is 0
// index is 1
// index is 2

下面是一般情況下這種循環(huán)方式的格式:

for initialization; condition; increment {
    statements
}

和 C 語(yǔ)言中一樣,分號(hào)將循環(huán)的定義分為 3 個(gè)部分舶替,不同的是令境,Swift 不需要使用圓括號(hào)將“initialization; condition; increment”包括起來(lái)。

這個(gè)循環(huán)執(zhí)行流程如下:

  1. 循環(huán)首次啟動(dòng)時(shí)顾瞪,初始化表達(dá)式( initialization expression )被調(diào)用一次舔庶,用來(lái)初始化循環(huán)所需的所有常量和變量。
  2. 條件表達(dá)式(condition expression)被調(diào)用陈醒,如果表達(dá)式調(diào)用結(jié)果為false惕橙,循環(huán)結(jié)束,繼續(xù)執(zhí)行for循環(huán)關(guān)閉大括號(hào)(})之后的代碼钉跷。如果表達(dá)式調(diào)用結(jié)果為true弥鹦,則會(huì)執(zhí)行大括號(hào)內(nèi)部的代碼。
  3. 執(zhí)行所有語(yǔ)句之后爷辙,執(zhí)行遞增表達(dá)式(increment expression)彬坏。通常會(huì)增加或減少計(jì)數(shù)器的值,或者根據(jù)語(yǔ)句輸出來(lái)修改某一個(gè)初始化的變量膝晾。當(dāng)遞增表達(dá)式運(yùn)行完成后栓始,重復(fù)執(zhí)行第 2 步,條件表達(dá)式會(huì)再次執(zhí)行血当。

在初始化表達(dá)式中聲明的常量和變量(比如var index = 0)只在for循環(huán)的生命周期里有效幻赚。如果想在循環(huán)結(jié)束后訪問(wèn)index的值禀忆,必須要在循環(huán)生命周期開(kāi)始前聲明index

var index: Int
for index = 0; index < 3; ++index {
    print("index is \(index)")
}
// index is 0
// index is 1
// index is 2
print("The loop statements were executed \(index) times")
// 輸出 "The loop statements were executed 3 times

注意index在循環(huán)結(jié)束后最終的值是3而不是2落恼。最后一次調(diào)用遞增表達(dá)式++index會(huì)將index設(shè)置為3油湖,從而導(dǎo)致index < 3條件為false,并終止循環(huán)领跛。

While 循環(huán)

while循環(huán)運(yùn)行一系列語(yǔ)句直到條件變成false乏德。這類(lèi)循環(huán)適合使用在第一次迭代前迭代次數(shù)未知的情況下。Swift 提供兩種while循環(huán)形式:

  • while循環(huán)吠昭,每次在循環(huán)開(kāi)始時(shí)計(jì)算條件是否符合喊括;
  • repeat-while循環(huán),每次在循環(huán)結(jié)束時(shí)計(jì)算條件是否符合矢棚。

While

while循環(huán)從計(jì)算單一條件開(kāi)始郑什。如果條件為true,會(huì)重復(fù)運(yùn)行一系列語(yǔ)句蒲肋,直到條件變?yōu)?code>false蘑拯。

下面是一般情況下 while 循環(huán)格式:

while condition {  
    statements
}

下面的例子來(lái)玩一個(gè)叫做蛇和梯子的小游戲,也叫做滑道和梯子:

image
image

游戲的規(guī)則如下:

  • 游戲盤(pán)面包括 25 個(gè)方格兜粘,游戲目標(biāo)是達(dá)到或者超過(guò)第 25 個(gè)方格申窘;
  • 每一輪,通過(guò)擲一個(gè) 6 邊的骰子來(lái)確定移動(dòng)方塊的步數(shù)孔轴,移動(dòng)的路線由上圖中橫向的虛線所示剃法;
  • 如果在某輪結(jié)束,移動(dòng)到了梯子的底部路鹰,可以順著梯子爬上去贷洲;
  • 如果在某輪結(jié)束,移動(dòng)到了蛇的頭部晋柱,會(huì)順著蛇的身體滑下去优构。

游戲盤(pán)面可以使用一個(gè)Int數(shù)組來(lái)表達(dá)。數(shù)組的長(zhǎng)度由一個(gè)finalSquare常量?jī)?chǔ)存雁竞,用來(lái)初始化數(shù)組和檢測(cè)最終勝利條件钦椭。游戲盤(pán)面由 26 個(gè) Int 0 值初始化,而不是 25 個(gè)(由025浓领,一共 26 個(gè)):

let finalSquare = 25
var board = [Int](count: finalSquare + 1, repeatedValue: 0)

一些方塊被設(shè)置成有蛇或者梯子的指定值玉凯。梯子底部的方塊是一個(gè)正值,使你可以向上移動(dòng)联贩,蛇頭處的方塊是一個(gè)負(fù)值漫仆,會(huì)讓你向下移動(dòng):

board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

3 號(hào)方塊是梯子的底部,會(huì)讓你向上移動(dòng)到 11 號(hào)方格泪幌,我們使用board[03]等于+08(來(lái)表示113之間的差值)盲厌。使用一元加運(yùn)算符(+i)是為了和一元減運(yùn)算符(-i)對(duì)稱(chēng)署照,為了讓盤(pán)面代碼整齊,小于 10 的數(shù)字都使用 0 補(bǔ)齊(這些風(fēng)格上的調(diào)整都不是必須的吗浩,只是為了讓代碼看起來(lái)更加整潔)建芙。

玩家由左下角編號(hào)為 0 的方格開(kāi)始游戲。一般來(lái)說(shuō)玩家第一次擲骰子后才會(huì)進(jìn)入游戲盤(pán)面:

var square = 0
var diceRoll = 0
while square < finalSquare {
    // 擲骰子
    if ++diceRoll == 7 { diceRoll = 1 }
    // 根據(jù)點(diǎn)數(shù)移動(dòng)
    square += diceRoll
    if square < board.count {
        // 如果玩家還在棋盤(pán)上懂扼,順著梯子爬上去或者順著蛇滑下去
        square += board[square]
    }
}
print("Game over!")

本例中使用了最簡(jiǎn)單的方法來(lái)模擬擲骰子禁荸。 diceRoll的值并不是一個(gè)隨機(jī)數(shù),而是以0為初始值阀湿,之后每一次while循環(huán)赶熟,diceRoll的值使用前置自增操作符(++i)來(lái)自增 1 ,然后檢測(cè)是否超出了最大值陷嘴。++diceRoll調(diào)用完成映砖,返回值等于diceRoll自增后的值。任何時(shí)候如果diceRoll的值等于7時(shí)灾挨,就超過(guò)了骰子的最大值邑退,會(huì)被重置為1。所以diceRoll的取值順序會(huì)一直是1劳澄,2地技,34浴骂,5乓土,6宪潮,1溯警,2

擲完骰子后狡相,玩家向前移動(dòng)diceRoll個(gè)方格梯轻,如果玩家移動(dòng)超過(guò)了第 25 個(gè)方格,這個(gè)時(shí)候游戲結(jié)束尽棕,相應(yīng)地喳挑,代碼會(huì)在square增加board[square]的值向前或向后移動(dòng)(遇到了梯子或者蛇)之前,檢測(cè)square的值是否小于boardcount屬性滔悉。

如果沒(méi)有這個(gè)檢測(cè)(square < board.count)伊诵,board[square]可能會(huì)越界訪問(wèn)board數(shù)組,導(dǎo)致錯(cuò)誤回官。例如如果square等于26曹宴, 代碼會(huì)去嘗試訪問(wèn)board[26],超過(guò)數(shù)組的長(zhǎng)度歉提。

當(dāng)本輪while循環(huán)運(yùn)行完畢笛坦,會(huì)再檢測(cè)循環(huán)條件是否需要再運(yùn)行一次循環(huán)区转。如果玩家移動(dòng)到或者超過(guò)第 25 個(gè)方格,循環(huán)條件結(jié)果為false版扩,此時(shí)游戲結(jié)束废离。

while 循環(huán)比較適合本例中的這種情況,因?yàn)樵?while 循環(huán)開(kāi)始時(shí)礁芦,我們并不知道游戲的長(zhǎng)度或者循環(huán)的次數(shù)蜻韭,只有在達(dá)成指定條件時(shí)循環(huán)才會(huì)結(jié)束。

Repeat-While

while循環(huán)的另外一種形式是repeat-while柿扣,它和while的區(qū)別是在判斷循環(huán)條件之前湘捎,先執(zhí)行一次循環(huán)的代碼塊,然后重復(fù)循環(huán)直到條件為false窄刘。

注意:
Swift語(yǔ)言的repeat-while循環(huán)合其他語(yǔ)言中的do-while循環(huán)是類(lèi)似的窥妇。

下面是一般情況下 repeat-while循環(huán)的格式:

repeat {
    statements
} while condition

還是蛇和梯子的游戲,使用repeat-while循環(huán)來(lái)替代while循環(huán)娩践。finalSquare活翩、boardsquarediceRoll的值初始化同while循環(huán)一樣:

let finalSquare = 25
var board = [Int](count: finalSquare + 1, repeatedValue: 0)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
var square = 0
var diceRoll = 0

repeat-while的循環(huán)版本翻伺,循環(huán)中第一步就需要去檢測(cè)是否在梯子或者蛇的方塊上材泄。沒(méi)有梯子會(huì)讓玩家直接上到第 25 個(gè)方格,所以玩家不會(huì)通過(guò)梯子直接贏得游戲吨岭。這樣在循環(huán)開(kāi)始時(shí)先檢測(cè)是否踩在梯子或者蛇上是安全的拉宗。

游戲開(kāi)始時(shí),玩家在第 0 個(gè)方格上辣辫,board[0]一直等于 0旦事, 不會(huì)有什么影響:

repeat {
    // 順著梯子爬上去或者順著蛇滑下去
    square += board[square]
    // 擲骰子
    if ++diceRoll == 7 { diceRoll = 1 }
    // 根據(jù)點(diǎn)數(shù)移動(dòng)
    square += diceRoll
} while square < finalSquare
print("Game over!")

檢測(cè)完玩家是否踩在梯子或者蛇上之后,開(kāi)始擲骰子急灭,然后玩家向前移動(dòng)diceRoll個(gè)方格姐浮,本輪循環(huán)結(jié)束。

循環(huán)條件(while square < finalSquare)和while方式相同葬馋,但是只會(huì)在循環(huán)結(jié)束后進(jìn)行計(jì)算卖鲤。在這個(gè)游戲中,repeat-while表現(xiàn)得比while循環(huán)更好畴嘶。repeat-while方式會(huì)在條件判斷square沒(méi)有超出后直接運(yùn)行square += board[square]蛋逾,這種方式可以去掉while版本中的數(shù)組越界判斷。

條件語(yǔ)句

根據(jù)特定的條件執(zhí)行特定的代碼通常是十分有用的窗悯,例如:當(dāng)錯(cuò)誤發(fā)生時(shí)区匣,可能想運(yùn)行額外的代碼;或者蟀瞧,當(dāng)輸入的值太大或太小時(shí)沉颂,向用戶顯示一條消息等条摸。要實(shí)現(xiàn)這些功能,就需要使用條件語(yǔ)句铸屉。

Swift 提供兩種類(lèi)型的條件語(yǔ)句:if語(yǔ)句和switch語(yǔ)句钉蒲。通常,當(dāng)條件較為簡(jiǎn)單且可能的情況很少時(shí)彻坛,使用if語(yǔ)句顷啼。而switch語(yǔ)句更適用于條件較復(fù)雜、可能情況較多且需要用到模式匹配(pattern-matching)的情境昌屉。

If

if語(yǔ)句最簡(jiǎn)單的形式就是只包含一個(gè)條件钙蒙,當(dāng)且僅當(dāng)該條件為true時(shí),才執(zhí)行相關(guān)代碼:

var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
    print("It's very cold. Consider wearing a scarf.")
}
// 輸出 "It's very cold. Consider wearing a scarf."

上面的例子會(huì)判斷溫度是否小于等于 32 華氏度(水的冰點(diǎn))间驮。如果是躬厌,則打印一條消息;否則竞帽,不打印任何消息扛施,繼續(xù)執(zhí)行if塊后面的代碼。

當(dāng)然屹篓,if語(yǔ)句允許二選一疙渣,也就是當(dāng)條件為false時(shí),執(zhí)行 else 語(yǔ)句

temperatureInFahrenheit = 40
if temperatureInFahrenheit <= 32 {
    print("It's very cold. Consider wearing a scarf.")
} else {
    print("It's not that cold. Wear a t-shirt.")
}
// 輸出 "It's not that cold. Wear a t-shirt."

顯然堆巧,這兩條分支中總有一條會(huì)被執(zhí)行妄荔。由于溫度已升至 40 華氏度,不算太冷谍肤,沒(méi)必要再圍圍巾——因此啦租,else分支就被觸發(fā)了。

可以把多個(gè)if語(yǔ)句鏈接在一起谣沸,像下面這樣:

temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
    print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
    print("It's really warm. Don't forget to wear sunscreen.")
} else {
    print("It's not that cold. Wear a t-shirt.")
}
// 輸出 "It's really warm. Don't forget to wear sunscreen."

在上面的例子中刷钢,額外的if語(yǔ)句用于判斷是不是特別熱。而最后的else語(yǔ)句被保留了下來(lái)乳附,用于打印既不冷也不熱時(shí)的消息。

實(shí)際上伴澄,最后的else語(yǔ)句是可選的:

temperatureInFahrenheit = 72
if temperatureInFahrenheit <= 32 {
    print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
    print("It's really warm. Don't forget to wear sunscreen.")
}

在這個(gè)例子中赋除,由于既不冷也不熱,所以不會(huì)觸發(fā)ifelse if分支非凌,也就不會(huì)打印任何消息举农。

Switch

switch語(yǔ)句會(huì)嘗試把某個(gè)值與若干個(gè)模式(pattern)進(jìn)行匹配。根據(jù)第一個(gè)匹配成功的模式敞嗡,switch語(yǔ)句會(huì)執(zhí)行對(duì)應(yīng)的代碼颁糟。當(dāng)有可能的情況較多時(shí)航背,通常用switch語(yǔ)句替換if語(yǔ)句。

switch語(yǔ)句最簡(jiǎn)單的形式就是把某個(gè)值與一個(gè)或若干個(gè)相同類(lèi)型的值作比較:

switch some value to consider {
case value 1:
    respond to value 1
case value 2, value 3:
    respond to value 2 or 3
default:
    otherwise, do something else
}

switch語(yǔ)句都由多個(gè) case 構(gòu)成棱貌。為了匹配某些更特定的值玖媚,Swift 提供了幾種更復(fù)雜的匹配模式,這些模式將在本節(jié)的稍后部分提到婚脱。

每一個(gè) case 都是代碼執(zhí)行的一條分支今魔,這與if語(yǔ)句類(lèi)似。與之不同的是障贸,switch語(yǔ)句會(huì)決定哪一條分支應(yīng)該被執(zhí)行错森。

switch語(yǔ)句必須是完備的。這就是說(shuō)篮洁,每一個(gè)可能的值都必須至少有一個(gè) case 分支與之對(duì)應(yīng)涩维。在某些不可能涵蓋所有值的情況下,可以使用默認(rèn)(default)分支滿足該要求袁波,這個(gè)默認(rèn)分支必須在switch語(yǔ)句的最后面激挪。

下面的例子使用switch語(yǔ)句來(lái)匹配一個(gè)名為someCharacter的小寫(xiě)字符:

let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
    print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
    print("\(someCharacter) is a consonant")
default:
    print("\(someCharacter) is not a vowel or a consonant")
}
// 輸出 "e is a vowel"

在這個(gè)例子中,第一個(gè) case 分支用于匹配五個(gè)元音锋叨,第二個(gè) case 分支用于匹配所有的輔音垄分。

由于為其它可能的字符寫(xiě) case 分支沒(méi)有實(shí)際的意義,因此在這個(gè)例子中使用了默認(rèn)分支來(lái)處理剩下的既不是元音也不是輔音的字符——這就保證了switch語(yǔ)句的完備性娃磺。

不存在隱式的貫穿(No Implicit Fallthrough)

與 C 語(yǔ)言和 Objective-C 中的switch語(yǔ)句不同薄湿,在 Swift 中,當(dāng)匹配的 case 分支中的代碼執(zhí)行完畢后偷卧,程序會(huì)終止switch語(yǔ)句豺瘤,而不會(huì)繼續(xù)執(zhí)行下一個(gè) case 分支听诸。這也就是說(shuō)坐求,不需要在 case 分支中顯式地使用break語(yǔ)句。這使得switch語(yǔ)句更安全、更易用,也避免了因忘記寫(xiě)break語(yǔ)句而產(chǎn)生的錯(cuò)誤徐钠。

注意:
雖然在Swift中break不是必須的摊崭,但依然可以在 case 分支中的代碼執(zhí)行完畢前使用break跳出。

每一個(gè) case 分支都必須包含至少一條語(yǔ)句。像下面這樣書(shū)寫(xiě)代碼是無(wú)效的窘问,因?yàn)榈谝粋€(gè) case 分支是空的:

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a":
case "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// this will report a compile-time error

不像 C 語(yǔ)言里的switch語(yǔ)句,在 Swift 中逗威,switch語(yǔ)句不會(huì)同時(shí)匹配"a""A"侦高。相反的计螺,上面的代碼會(huì)引起編譯期錯(cuò)誤:case "a": does not contain any executable statements——這就避免了意外地從一個(gè) case 分支貫穿到另外一個(gè)秦忿,使得代碼更安全呐萨、也更直觀北秽。

一個(gè) case 也可以包含多個(gè)模式贺氓,用逗號(hào)把它們分開(kāi)(如果太長(zhǎng)了也可以分行寫(xiě)):

switch some value to consider {
case value 1, value 2:
    statements
}

區(qū)間匹配

case 分支的模式也可以是一個(gè)值的區(qū)間。下面的例子展示了如何使用區(qū)間匹配來(lái)輸出任意數(shù)字對(duì)應(yīng)的自然語(yǔ)言格式:

let approximateCount = 62
let countedThings = "moons orbiting Saturn"
var naturalCount: String
switch approximateCount {
case 0:
    naturalCount = "no"
case 1..<5:
    naturalCount = "a few"
case 5..<12:
    naturalCount = "several"
case 12..<100:
    naturalCount = "dozens of"
case 100..<1000:
    naturalCount = "hundreds of"
default:
    naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// 輸出 "There are dozens of moons orbiting Saturn."

在上例中,approximateCount在一個(gè)switch聲明中被估值蔑水。每一個(gè)case都與之進(jìn)行比較邢锯。因?yàn)?code>approximateCount落在了12到100的區(qū)間,所以naturalCount等于"dozens of"值搀别,并且此后這段執(zhí)行跳出了switch聲明丹擎。

注意:
閉區(qū)間操作符(...)以及半開(kāi)區(qū)間操作符(..<)功能被重載去返回IntervalTypeRange。一個(gè)區(qū)間可以決定他是否包含特定的元素歇父,就像當(dāng)匹配一個(gè)switch聲明的case一樣蒂培。區(qū)間是一個(gè)連續(xù)值的集合,可以用for-in語(yǔ)句遍歷它榜苫。

元組(Tuple)

我們可以使用元組在同一個(gè)switch語(yǔ)句中測(cè)試多個(gè)值护戳。元組中的元素可以是值,也可以是區(qū)間单刁。另外灸异,使用下劃線(_)來(lái)匹配所有可能的值。

下面的例子展示了如何使用一個(gè)(Int, Int)類(lèi)型的元組來(lái)分類(lèi)下圖中的點(diǎn)(x, y):

let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    print("(0, 0) is at the origin")
case (_, 0):
    print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
    print("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
    print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// 輸出 "(1, 1) is inside the box"
image
image

在上面的例子中羔飞,switch語(yǔ)句會(huì)判斷某個(gè)點(diǎn)是否是原點(diǎn)(0, 0)肺樟,是否在紅色的x軸上,是否在黃色y軸上逻淌,是否在一個(gè)以原點(diǎn)為中心的4x4的矩形里么伯,或者在這個(gè)矩形外面。

不像 C 語(yǔ)言卡儒,Swift 允許多個(gè) case 匹配同一個(gè)值田柔。實(shí)際上,在這個(gè)例子中骨望,點(diǎn)(0, 0)可以匹配所有四個(gè) case硬爆。但是,如果存在多個(gè)匹配擎鸠,那么只會(huì)執(zhí)行第一個(gè)被匹配到的 case 分支缀磕。考慮點(diǎn)(0, 0)會(huì)首先匹配case (0, 0)劣光,因此剩下的能夠匹配(0, 0)的 case 分支都會(huì)被忽視掉袜蚕。

值綁定(Value Bindings)

case 分支的模式允許將匹配的值綁定到一個(gè)臨時(shí)的常量或變量,這些常量或變量在該 case 分支里就可以被引用了——這種行為被稱(chēng)為值綁定(value binding)绢涡。

下面的例子展示了如何在一個(gè)(Int, Int)類(lèi)型的元組中使用值綁定來(lái)分類(lèi)下圖中的點(diǎn)(x, y):

let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
    print("on the x-axis with an x value of \(x)")
case (0, let y):
    print("on the y-axis with a y value of \(y)")
case let (x, y):
    print("somewhere else at (\(x), \(y))")
}
// 輸出 "on the x-axis with an x value of 2"
image
image

在上面的例子中牲剃,switch語(yǔ)句會(huì)判斷某個(gè)點(diǎn)是否在紅色的x軸上,是否在黃色y軸上雄可,或者不在坐標(biāo)軸上凿傅。

這三個(gè) case 都聲明了常量xy的占位符缠犀,用于臨時(shí)獲取元組anotherPoint的一個(gè)或兩個(gè)值。第一個(gè) case ——case (let x, 0)將匹配一個(gè)縱坐標(biāo)為0的點(diǎn)狭归,并把這個(gè)點(diǎn)的橫坐標(biāo)賦給臨時(shí)的常量x夭坪。類(lèi)似的文判,第二個(gè) case ——case (0, let y)將匹配一個(gè)橫坐標(biāo)為0的點(diǎn)过椎,并把這個(gè)點(diǎn)的縱坐標(biāo)賦給臨時(shí)的常量y

一旦聲明了這些臨時(shí)的常量戏仓,它們就可以在其對(duì)應(yīng)的 case 分支里引用疚宇。在這個(gè)例子中,它們用于簡(jiǎn)化print(_:separator:terminator:)的書(shū)寫(xiě)赏殃。

請(qǐng)注意敷待,這個(gè)switch語(yǔ)句不包含默認(rèn)分支。這是因?yàn)樽詈笠粋€(gè) case ——case let(x, y)聲明了一個(gè)可以匹配余下所有值的元組仁热。這使得switch語(yǔ)句已經(jīng)完備了榜揖,因此不需要再書(shū)寫(xiě)默認(rèn)分支。

在上面的例子中抗蠢,xy是常量举哟,這是因?yàn)闆](méi)有必要在其對(duì)應(yīng)的 case 分支中修改它們的值。然而迅矛,它們也可以是變量——程序?qū)?huì)創(chuàng)建臨時(shí)變量妨猩,并用相應(yīng)的值初始化它。修改這些變量只會(huì)影響其對(duì)應(yīng)的 case 分支秽褒。

Where

case 分支的模式可以使用where語(yǔ)句來(lái)判斷額外的條件壶硅。

下面的例子把下圖中的點(diǎn)(x, y)進(jìn)行了分類(lèi):

let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
    print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
    print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
    print("(\(x), \(y)) is just some arbitrary point")
}
// 輸出 "(1, -1) is on the line x == -y"
image
image

在上面的例子中,switch語(yǔ)句會(huì)判斷某個(gè)點(diǎn)是否在綠色的對(duì)角線x == y上销斟,是否在紫色的對(duì)角線x == -y上庐椒,或者不在對(duì)角線上。

這三個(gè) case 都聲明了常量xy的占位符蚂踊,用于臨時(shí)獲取元組yetAnotherPoint的兩個(gè)值约谈。這些常量被用作where語(yǔ)句的一部分,從而創(chuàng)建一個(gè)動(dòng)態(tài)的過(guò)濾器(filter)悴势。當(dāng)且僅當(dāng)where語(yǔ)句的條件為true時(shí)窗宇,匹配到的 case 分支才會(huì)被執(zhí)行。

就像是值綁定中的例子特纤,由于最后一個(gè) case 分支匹配了余下所有可能的值军俊,switch語(yǔ)句就已經(jīng)完備了,因此不需要再書(shū)寫(xiě)默認(rèn)分支捧存。

控制轉(zhuǎn)移語(yǔ)句(Control Transfer Statements)

控制轉(zhuǎn)移語(yǔ)句改變代碼的執(zhí)行順序粪躬,通過(guò)它可以實(shí)現(xiàn)代碼的跳轉(zhuǎn)担败。Swift 有五種控制轉(zhuǎn)移語(yǔ)句:

  • continue
  • break
  • fallthrough
  • return
  • throw

我們將會(huì)在下面討論continuebreakfallthrough語(yǔ)句镰官。

Continue

continue語(yǔ)句告訴一個(gè)循環(huán)體立刻停止本次循環(huán)迭代提前,重新開(kāi)始下次循環(huán)迭代。就好像在說(shuō)“本次循環(huán)迭代我已經(jīng)執(zhí)行完了”泳唠,但是并不會(huì)離開(kāi)整個(gè)循環(huán)體狈网。

注意:
在一個(gè)帶有條件和遞增的for循環(huán)體中,調(diào)用continue語(yǔ)句后笨腥,迭代增量仍然會(huì)被計(jì)算求值拓哺。循環(huán)體繼續(xù)像往常一樣工作,僅僅只是循環(huán)體中的執(zhí)行代碼會(huì)被跳過(guò)脖母。

下面的例子把一個(gè)小寫(xiě)字符串中的元音字母和空格字符移除士鸥,生成了一個(gè)含義模糊的短句:

let puzzleInput = "great minds think alike"
var puzzleOutput = ""
for character in puzzleInput.characters {
    switch character {
    case "a", "e", "i", "o", "u", " ":
        continue
    default:
        puzzleOutput.append(character)
    }
}
print(puzzleOutput)
// 輸出 "grtmndsthnklk"

在上面的代碼中,只要匹配到元音字母或者空格字符谆级,就調(diào)用continue語(yǔ)句烤礁,使本次循環(huán)迭代結(jié)束,從新開(kāi)始下次循環(huán)迭代肥照。這種行為使switch匹配到元音字母和空格字符時(shí)不做處理脚仔,而不是讓每一個(gè)匹配到的字符都被打印。

Break

break語(yǔ)句會(huì)立刻結(jié)束整個(gè)控制流的執(zhí)行建峭。當(dāng)想要更早的結(jié)束一個(gè)switch代碼塊或者一個(gè)循環(huán)體時(shí)玻侥,都可以使用break語(yǔ)句。

循環(huán)語(yǔ)句中的 break

當(dāng)在一個(gè)循環(huán)體中使用break時(shí)亿蒸,會(huì)立刻中斷該循環(huán)體的執(zhí)行凑兰,然后跳轉(zhuǎn)到表示循環(huán)體結(jié)束的大括號(hào)(})后的第一行代碼。不會(huì)再有本次循環(huán)迭代的代碼被執(zhí)行边锁,也不會(huì)再有下次的循環(huán)迭代產(chǎn)生姑食。

Switch 語(yǔ)句中的 break

當(dāng)在一個(gè)switch代碼塊中使用break時(shí),會(huì)立即中斷該switch代碼塊的執(zhí)行茅坛,并且跳轉(zhuǎn)到表示switch代碼塊結(jié)束的大括號(hào)(})后的第一行代碼音半。

這種特性可以被用來(lái)匹配或者忽略一個(gè)或多個(gè)分支。因?yàn)?Swift 的switch需要包含所有的分支而且不允許有為空的分支贡蓖,有時(shí)為了使意圖更明顯曹鸠,需要特意匹配或者忽略某個(gè)分支。那么當(dāng)想忽略某個(gè)分支時(shí)斥铺,可以在該分支內(nèi)寫(xiě)上break語(yǔ)句彻桃。當(dāng)那個(gè)分支被匹配到時(shí),分支內(nèi)的break語(yǔ)句立即結(jié)束switch代碼塊晾蜘。

注意:
當(dāng)一個(gè)switch分支僅僅包含注釋時(shí)邻眷,會(huì)被報(bào)編譯時(shí)錯(cuò)誤眠屎。注釋不是代碼語(yǔ)句而且也不能讓switch分支達(dá)到被忽略的效果∷寥模總是可以使用break來(lái)忽略某個(gè)分支改衩。

下面的例子通過(guò)switch來(lái)判斷一個(gè)Character值是否代表下面四種語(yǔ)言之一。為了簡(jiǎn)潔驯镊,多個(gè)值被包含在了同一個(gè)分支情況中葫督。

let numberSymbol: Character = "三"  // 簡(jiǎn)體中文里的數(shù)字 3
var possibleIntegerValue: Int?
switch numberSymbol {
case "1", "?", "一", "?":
    possibleIntegerValue = 1
case "2", "?", "二", "?":
    possibleIntegerValue = 2
case "3", "?", "三", "?":
    possibleIntegerValue = 3
case "4", "?", "四", "?":
    possibleIntegerValue = 4
default:
    break
}
if let integerValue = possibleIntegerValue {
    print("The integer value of \(numberSymbol) is \(integerValue).")
} else {
    print("An integer value could not be found for \(numberSymbol).")
}
// 輸出 "The integer value of 三 is 3."

這個(gè)例子檢查numberSymbol是否是拉丁,阿拉伯阿宅,中文或者泰語(yǔ)中的14之一候衍。如果被匹配到,該switch分支語(yǔ)句給Int?類(lèi)型變量possibleIntegerValue設(shè)置一個(gè)整數(shù)值洒放。

當(dāng)switch代碼塊執(zhí)行完后,接下來(lái)的代碼通過(guò)使用可選綁定來(lái)判斷possibleIntegerValue是否曾經(jīng)被設(shè)置過(guò)值滨砍。因?yàn)槭强蛇x類(lèi)型的緣故往湿,possibleIntegerValue有一個(gè)隱式的初始值nil,所以僅僅當(dāng)possibleIntegerValue曾被switch代碼塊的前四個(gè)分支中的某個(gè)設(shè)置過(guò)一個(gè)值時(shí)惋戏,可選的綁定將會(huì)被判定為成功领追。

在上面的例子中,想要把Character所有的的可能性都枚舉出來(lái)是不現(xiàn)實(shí)的响逢,所以使用default分支來(lái)包含所有上面沒(méi)有匹配到字符的情況绒窑。由于這個(gè)default分支不需要執(zhí)行任何動(dòng)作,所以它只寫(xiě)了一條break語(yǔ)句舔亭。一旦落入到default分支中后些膨,break語(yǔ)句就完成了該分支的所有代碼操作,代碼繼續(xù)向下钦铺,開(kāi)始執(zhí)行if let語(yǔ)句订雾。

貫穿(Fallthrough)

Swift 中的switch不會(huì)從上一個(gè) case 分支落入到下一個(gè) case 分支中。相反矛洞,只要第一個(gè)匹配到的 case 分支完成了它需要執(zhí)行的語(yǔ)句洼哎,整個(gè)switch代碼塊完成了它的執(zhí)行。相比之下沼本,C 語(yǔ)言要求顯式地插入break語(yǔ)句到每個(gè)switch分支的末尾來(lái)阻止自動(dòng)落入到下一個(gè) case 分支中噩峦。Swift 的這種避免默認(rèn)落入到下一個(gè)分支中的特性意味著它的switch 功能要比 C 語(yǔ)言的更加清晰和可預(yù)測(cè),可以避免無(wú)意識(shí)地執(zhí)行多個(gè) case 分支從而引發(fā)的錯(cuò)誤抽兆。

如果確實(shí)需要 C 風(fēng)格的貫穿的特性啃洋,可以在每個(gè)需要該特性的 case 分支中使用fallthrough關(guān)鍵字。下面的例子使用fallthrough來(lái)創(chuàng)建一個(gè)數(shù)字的描述語(yǔ)句滩愁。

let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
    description += " a prime number, and also"
    fallthrough
default:
    description += " an integer."
}
print(description)
// 輸出 "The number 5 is a prime number, and also an integer."

這個(gè)例子定義了一個(gè)String類(lèi)型的變量description并且給它設(shè)置了一個(gè)初始值。函數(shù)使用switch邏輯來(lái)判斷integerToDescribe變量的值瞧筛。當(dāng)integerToDescribe的值屬于列表中的質(zhì)數(shù)之一時(shí),該函數(shù)添加一段文字在description后导盅,來(lái)表明這個(gè)是數(shù)字是一個(gè)質(zhì)數(shù)较幌。然后它使用fallthrough關(guān)鍵字來(lái)“貫穿”到default分支中。default分支添加一段額外的文字在description的最后白翻,至此switch代碼塊執(zhí)行完了乍炉。

如果integerToDescribe的值不屬于列表中的任何質(zhì)數(shù),那么它不會(huì)匹配到第一個(gè)switch分支滤馍。而這里沒(méi)有其他特別的分支情況岛琼,所以integerToDescribe匹配到包含所有的default分支中。

當(dāng)switch代碼塊執(zhí)行完后巢株,使用print(_:separator:terminator:)函數(shù)打印該數(shù)字的描述槐瑞。在這個(gè)例子中,數(shù)字5被準(zhǔn)確的識(shí)別為了一個(gè)質(zhì)數(shù)阁苞。

注意:
fallthrough關(guān)鍵字不會(huì)檢查它下一個(gè)將會(huì)落入執(zhí)行的 case 中的匹配條件困檩。fallthrough簡(jiǎn)單地使代碼執(zhí)行繼續(xù)連接到下一個(gè) case 中的執(zhí)行代碼那槽,這和 C 語(yǔ)言標(biāo)準(zhǔn)中的switch語(yǔ)句特性是一樣的悼沿。

帶標(biāo)簽的語(yǔ)句

在 Swift 中,可以在循環(huán)體和switch代碼塊中嵌套循環(huán)體和switch代碼塊來(lái)創(chuàng)造復(fù)雜的控制流結(jié)構(gòu)。然而,循環(huán)體和switch代碼塊兩者都可以使用break語(yǔ)句來(lái)提前結(jié)束整個(gè)方法體。因此榨汤,顯式地指明break語(yǔ)句想要終止的是哪個(gè)循環(huán)體或者switch代碼塊圃验,會(huì)很有用栗精。類(lèi)似地瞻鹏,如果有許多嵌套的循環(huán)體悲立,顯式指明continue語(yǔ)句想要影響哪一個(gè)循環(huán)體也會(huì)非常有用。

為了實(shí)現(xiàn)這個(gè)目的新博,可以使用標(biāo)簽來(lái)標(biāo)記一個(gè)循環(huán)體或者switch代碼塊薪夕,當(dāng)使用break或者continue時(shí),帶上這個(gè)標(biāo)簽赫悄,可以控制該標(biāo)簽代表對(duì)象的中斷或者執(zhí)行原献。

產(chǎn)生一個(gè)帶標(biāo)簽的語(yǔ)句是通過(guò)在該語(yǔ)句的關(guān)鍵詞的同一行前面放置一個(gè)標(biāo)簽,并且該標(biāo)簽后面還需帶著一個(gè)冒號(hào)埂淮。下面是一個(gè)while循環(huán)體的語(yǔ)法姑隅,同樣的規(guī)則適用于所有的循環(huán)體和switch代碼塊。

label name: while condition {
    statements
}

下面的例子是在一個(gè)帶有標(biāo)簽的while循環(huán)體中調(diào)用breakcontinue語(yǔ)句倔撞,該循環(huán)體是前面章節(jié)中蛇和梯子的改編版本讲仰。這次,游戲增加了一條額外的規(guī)則:

  • 為了獲勝痪蝇,你必須剛好落在第 25 個(gè)方塊中鄙陡。

如果某次擲骰子使你的移動(dòng)超出第 25 個(gè)方塊冕房,你必須重新擲骰子,直到你擲出的骰子數(shù)剛好使你能落在第 25 個(gè)方塊中趁矾。

游戲的棋盤(pán)和之前一樣:

image
image

finalSquare耙册、boardsquarediceRoll值被和之前一樣的方式初始化:

let finalSquare = 25
var board = [Int](count: finalSquare + 1, repeatedValue: 0)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
var square = 0
var diceRoll = 0

這個(gè)版本的游戲使用while循環(huán)體和switch方法塊來(lái)實(shí)現(xiàn)游戲的邏輯愈魏。while循環(huán)體有一個(gè)標(biāo)簽名gameLoop觅玻,來(lái)表明它是蛇與梯子的主循環(huán)。

while循環(huán)體的條件判斷語(yǔ)句是while square !=finalSquare培漏,這表明你必須剛好落在方格25中溪厘。

gameLoop: while square != finalSquare {
    if ++diceRoll == 7 { diceRoll = 1 }
    switch square + diceRoll {
    case finalSquare:
        // 到達(dá)最后一個(gè)方塊,游戲結(jié)束
        break gameLoop
    case let newSquare where newSquare > finalSquare:
        // 超出最后一個(gè)方塊牌柄,再擲一次骰子
        continue gameLoop
    default:
        // 本次移動(dòng)有效
        square += diceRoll
        square += board[square]
    }
}
print("Game over!")

每次循環(huán)迭代開(kāi)始時(shí)擲骰子畸悬。與之前玩家擲完骰子就立即移動(dòng)不同,這里使用了switch來(lái)考慮每次移動(dòng)可能產(chǎn)生的結(jié)果珊佣,從而決定玩家本次是否能夠移動(dòng)蹋宦。

  • 如果骰子數(shù)剛好使玩家移動(dòng)到最終的方格里,游戲結(jié)束咒锻。break gameLoop語(yǔ)句跳轉(zhuǎn)控制去執(zhí)行while循環(huán)體后的第一行代碼冷冗,游戲結(jié)束。
  • 如果骰子數(shù)將會(huì)使玩家的移動(dòng)超出最后的方格惑艇,那么這種移動(dòng)是不合法的蒿辙,玩家需要重新擲骰子。continue gameLoop語(yǔ)句結(jié)束本次while循環(huán)的迭代滨巴,開(kāi)始下一次循環(huán)迭代思灌。
  • 在剩余的所有情況中,骰子數(shù)產(chǎn)生的都是合法的移動(dòng)恭取。玩家向前移動(dòng)骰子數(shù)個(gè)方格泰偿,然后游戲邏輯再處理玩家當(dāng)前是否處于蛇頭或者梯子的底部。本次循環(huán)迭代結(jié)束蜈垮,控制跳轉(zhuǎn)到while循環(huán)體的條件判斷語(yǔ)句處耗跛,再?zèng)Q定是否能夠繼續(xù)執(zhí)行下次循環(huán)迭代。

注意:
如果上述的break語(yǔ)句沒(méi)有使用gameLoop標(biāo)簽窃款,那么它將會(huì)中斷switch代碼塊而不是while循環(huán)體课兄。使用gameLoop標(biāo)簽清晰的表明了break想要中斷的是哪個(gè)代碼塊。
同時(shí)請(qǐng)注意晨继,當(dāng)調(diào)用continue gameLoop去跳轉(zhuǎn)到下一次循環(huán)迭代時(shí)烟阐,這里使用gameLoop標(biāo)簽并不是嚴(yán)格必須的。因?yàn)樵谶@個(gè)游戲中,只有一個(gè)循環(huán)體蜒茄,所以continue語(yǔ)句會(huì)影響到哪個(gè)循環(huán)體是沒(méi)有歧義的唉擂。然而,continue語(yǔ)句使用gameLoop標(biāo)簽也是沒(méi)有危害的檀葛。這樣做符合標(biāo)簽的使用規(guī)則玩祟,同時(shí)參照旁邊的break gameLoop,能夠使游戲的邏輯更加清晰和易于理解屿聋。

提前退出

if語(yǔ)句一樣空扎,guard的執(zhí)行取決于一個(gè)表達(dá)式的布爾值。我們可以使用guard語(yǔ)句來(lái)要求條件必須為真時(shí)润讥,以執(zhí)行guard語(yǔ)句后的代碼转锈。不同于if語(yǔ)句,一個(gè)guard語(yǔ)句總是有一個(gè)else分句楚殿,如果條件不為真則執(zhí)行else分句中的代碼撮慨。

func greet(person: [String: String]) {
    guard let name = person["name"] else {
        return
    }
    
    print("Hello \(name)")

    guard let location = person["location"] else {
        print("I hope the weather is nice near you.")
        return
    }
    
    print("I hope the weather is nice in \(location).")
}

greet(["name": "John"])
// prints "Hello John!"
// prints "I hope the weather is nice near you."
greet(["name": "Jane", "location": "Cupertino"])
// prints "Hello Jane!"
// prints "I hope the weather is nice in Cupertino."

如果guard語(yǔ)句的條件被滿足,則在保護(hù)語(yǔ)句的封閉大括號(hào)結(jié)束后繼續(xù)執(zhí)行代碼脆粥。任何使用了可選綁定作為條件的一部分并被分配了值的變量或常量對(duì)于剩下的保護(hù)語(yǔ)句出現(xiàn)的代碼段是可用的砌溺。

如果條件不被滿足,在else分支上的代碼就會(huì)被執(zhí)行变隔。這個(gè)分支必須轉(zhuǎn)移控制以退出guard語(yǔ)句出現(xiàn)的代碼段规伐。它可以用控制轉(zhuǎn)移語(yǔ)句如return,break,continue或者throw做這件事,或者調(diào)用一個(gè)不返回的方法或函數(shù)匣缘,例如fatalError()楷力。

相比于可以實(shí)現(xiàn)同樣功能的if語(yǔ)句,按需使用guard語(yǔ)句會(huì)提升我們代碼的可靠性孵户。
它可以使代碼連貫的被執(zhí)行而不需要將它包在else塊中,它可以使你處理違反要求的代碼使其接近要求岔留。

檢測(cè) API 可用性

Swift 有檢查 API 可用性的內(nèi)置支持夏哭,這可以確保我們不會(huì)不小心地使用對(duì)于當(dāng)前部署目標(biāo)不可用的 API。

編譯器使用 SDK 中的可用信息來(lái)驗(yàn)證我們的代碼中使用的所有 API 在項(xiàng)目指定的部署目標(biāo)上是否可用献联。如果我們嘗試使用一個(gè)不可用的 API竖配,Swift 會(huì)在編譯期報(bào)錯(cuò)。

我們使用一個(gè)可用性條件在一個(gè)ifguard語(yǔ)句中去有條件的執(zhí)行一段代碼里逆,這取決于我們想要使用的 API 是否在運(yùn)行時(shí)是可用的进胯。編譯器使用從可用性條件語(yǔ)句中獲取的信息去驗(yàn)證在代碼塊中調(diào)用的 API 是否都可用。

if #available(iOS 9, OSX 10.10, *) {
    // 在 iOS 使用 iOS 9 的 API, 在 OS X 使用 OS X v10.10 的 API
} else {
    // 使用先前版本的 iOS 和 OS X 的 API
}

以上可用性條件指定了在 iOS 系統(tǒng)上原押,if段的代碼僅會(huì)在 iOS 9 及更高版本的系統(tǒng)上執(zhí)行胁镐;在 OS X,僅會(huì)在 OS X v10.10 及更高版本的系統(tǒng)上執(zhí)行。最后一個(gè)參數(shù)盯漂,*颇玷,是必須寫(xiě)的,用于處理未來(lái)潛在的平臺(tái)就缆。

在它的一般形式中帖渠,可用性條件獲取了一系列平臺(tái)名字和版本。平臺(tái)名字可以是iOS竭宰,OSXwatchOS空郊。除了特定的主板本號(hào)像 iOS 8,我們可以指定較小的版本號(hào)像 iOS 8.3 以及 OS X v10.10.3切揭。

if #available(platform name version, ..., *) {
    statements to execute if the APIs are available
} else {
    fallback statements to execute if the APIs are unavailable
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末狞甚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子伴箩,更是在濱河造成了極大的恐慌入愧,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗤谚,死亡現(xiàn)場(chǎng)離奇詭異棺蛛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)巩步,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)旁赊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人椅野,你說(shuō)我怎么就攤上這事终畅。” “怎么了竟闪?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵离福,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我炼蛤,道長(zhǎng)妖爷,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任理朋,我火速辦了婚禮絮识,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嗽上。我一直安慰自己次舌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布兽愤。 她就那樣靜靜地躺著彼念,像睡著了一般挪圾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上国拇,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天洛史,我揣著相機(jī)與錄音,去河邊找鬼酱吝。 笑死也殖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的务热。 我是一名探鬼主播忆嗜,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼崎岂!你這毒婦竟也來(lái)了捆毫?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤冲甘,失蹤者是張志新(化名)和其女友劉穎绩卤,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體江醇,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡濒憋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了陶夜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凛驮。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖条辟,靈堂內(nèi)的尸體忽然破棺而出黔夭,到底是詐尸還是另有隱情,我是刑警寧澤羽嫡,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布本姥,位于F島的核電站,受9級(jí)特大地震影響杭棵,放射性物質(zhì)發(fā)生泄漏扣草。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一颜屠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鹰祸,春花似錦甫窟、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春浇衬,著一層夾襖步出監(jiān)牢的瞬間懒构,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工耘擂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胆剧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓醉冤,卻偏偏與公主長(zhǎng)得像秩霍,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蚁阳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Swift提供了多種控制流聲明铃绒。包括while循環(huán)來(lái)多次執(zhí)行一個(gè)任務(wù);if螺捐,guard和switch聲明來(lái)根據(jù)確定...
    BoomLee閱讀 1,950評(píng)論 0 3
  • Swift提供了各種控制流語(yǔ)句颠悬。 這些包括while循環(huán)來(lái)執(zhí)行多次任務(wù); if,guard和switch語(yǔ)句定血,以根...
    Joker_King閱讀 420評(píng)論 0 0
  • Swift提供了多種流程控制結(jié)構(gòu)赔癌,包括可以多次執(zhí)行任務(wù)的while循環(huán),基于特定條件基于特定條件選擇執(zhí)行不同代碼分...
    edison0428閱讀 1,251評(píng)論 0 0
  • 本章將會(huì)介紹 控制流For-In 循環(huán)While 循環(huán)If 條件語(yǔ)句Switch 語(yǔ)句控制轉(zhuǎn)移語(yǔ)句 continu...
    寒橋閱讀 723評(píng)論 0 0
  • 享受一下新出爐的獲獎(jiǎng)作品 《人生》 人生就像蹲坑,有時(shí)你已經(jīng)很努力了倔喂,但結(jié)果卻是個(gè)屁铝条。 《傷害》 一餓狼覓食到農(nóng)戶...
    wandly閱讀 241評(píng)論 0 0