在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ 控制流
方法 - Methods
關(guān)于 Swift
下標(biāo)腳本(Subscripts)
類和結(jié)構(gòu)體
類型轉(zhuǎn)換(Type Casting)
控制流
析構(gòu)過程(Deinitialization)
集合類型 (Collection Types)
構(gòu)造過程(Initialization)
Optional Chaining
枚舉(Enumerations)
自動(dòng)引用計(jì)數(shù)
繼承(Inheritance)
擴(kuò)展(Extensions)
泛型
字符串和字符(Strings and Characters)
函數(shù)(Functions)
高級運(yùn)算符
訪問控制
基本運(yùn)算符
嵌套類型
閉包(Closures)
協(xié)議
屬性 (Properties)

控制流

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

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

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

For 循環(huán)

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

  • for-in用來遍歷一個(gè)區(qū)間(range),序列(sequence),集合(collection),系列(progression)里面所有的元素執(zhí)行一系列語句。
  • for條件遞增(for-condition-increment)語句,用來重復(fù)執(zhí)行一系列語句直到達(dá)成特定條件達(dá)成,一般通過在每次循環(huán)完成后增加計(jì)數(shù)器的值來實(shí)現(xiàn)。

For-In

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

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

    for index in 1...5 {
        println("\(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

例子中用來進(jìn)行遍歷的元素是一組使用閉區(qū)間操作符(...)表示的從15的數(shù)字。index被賦值為閉區(qū)間中的第一個(gè)數(shù)字(1),然后循環(huán)中的語句被執(zhí)行一次。在本例中,這個(gè)循環(huán)只包含一個(gè)語句,用來輸出當(dāng)前index值所對應(yīng)的乘 5 乘法表結(jié)果。該語句執(zhí)行后,index的值被更新為閉區(qū)間中的第二個(gè)數(shù)字(2),之后println方法會(huì)再執(zhí)行一次。整個(gè)過程會(huì)進(jìn)行到閉區(qū)間結(jié)尾為止。

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

注意:
index常量只存在于循環(huán)的生命周期里。如果你想在循環(huán)完成后訪問index的值,又或者想讓index成為一個(gè)變量而不是常量,你必須在循環(huán)之前自己進(jìn)行聲明。

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

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

這個(gè)例子計(jì)算 base 這個(gè)數(shù)的 power 次冪(本例中,是310次冪),從130次冪)開始做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í)對值的訪問。

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

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

你也可以通過遍歷一個(gè)字典來訪問它的鍵值對(key-value pairs)。遍歷字典時(shí),字典的每項(xiàng)元素會(huì)以(key, value)元組的形式返回,你可以在for-in循環(huán)中使用顯式的常量名稱來解讀(key, value)元組。下面的例子中,字典的鍵(key)解讀為常量animalName,字典的值會(huì)被解讀為常量legCount

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

字典元素的遍歷順序和插入順序可能不同,字典的內(nèi)容在內(nèi)部是無序的,所以遍歷元素時(shí)不能保證順序。關(guān)于數(shù)組和字典,詳情參見集合類型。

除了數(shù)組和字典,你也可以使用for-in循環(huán)來遍歷字符串中的字符(Character):

    for character in "Hello" {
        println(character)
    }
    // H
    // e
    // l
    // l
    // o

For條件遞增(for-condition-increment)

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

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

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

for initialization; condition; increment {
statements
}

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

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

  1. 循環(huán)首次啟動(dòng)時(shí),初始化表達(dá)式(initialization expression)被調(diào)用一次,用來初始化循環(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)部的代碼(statements)。
  3. 執(zhí)行所有語句(statements)之后,執(zhí)行遞增表達(dá)式(increment expression)。通常會(huì)增加或減少計(jì)數(shù)器的值,或者根據(jù)語句(statements)輸出來修改某一個(gè)初始化的變量。當(dāng)遞增表達(dá)式運(yùn)行完成后,重復(fù)執(zhí)行第 2 步,條件表達(dá)式會(huì)再次執(zhí)行。

上述描述和循環(huán)格式等同于:

initialization
while condition {
statements
increment
}

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

    var index: Int
    for index = 0; index < 3; ++index {
        println("index is \(index)")
    }
    // index is 0
    // index is 1
    // index is 2
    println("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)行一系列語句直到條件變成false。這類循環(huán)適合使用在第一次迭代前迭代次數(shù)未知的情況下。Swift 提供兩種while循環(huán)形式:

  • while循環(huán),每次在循環(huán)開始時(shí)計(jì)算條件是否符合;
  • do-while循環(huán),每次在循環(huán)結(jié)束時(shí)計(jì)算條件是否符合。

While

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

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

while condition {
statements
}

下面的例子來玩一個(gè)叫做_蛇和梯子(Snakes and Ladders)_的小游戲,也叫做滑道和梯子(Chutes and Ladders)

http://wiki.jikexueyuan.com/project/swift-language-guide/images/Control_Flow_1.png" alt="Image of Control_Flow_1.png" />

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

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

游戲盤面可以使用一個(gè)Int數(shù)組來表達(dá)。數(shù)組的長度由一個(gè)finalSquare常量儲(chǔ)存,用來初始化數(shù)組和檢測最終勝利條件。游戲盤面由 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(來表示113之間的差值)。使用一元加運(yùn)算符(+i)是為了和一元減運(yùn)算符(-i)對稱,為了讓盤面代碼整齊,小于 10 的數(shù)字都使用 0 補(bǔ)齊(這些風(fēng)格上的調(diào)整都不是必須的,只是為了讓代碼看起來更加整潔)。

玩家由左下角編號(hào)為 0 的方格開始游戲。一般來說玩家第一次擲骰子后才會(huì)進(jì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 {
            // 如果玩家還在棋盤上,順著梯子爬上去或者順著蛇滑下去
            square += board[square]
        }
    }
    println("Game over!")

本例中使用了最簡單的方法來模擬擲骰子。 diceRoll的值并不是一個(gè)隨機(jī)數(shù),而是以0為初始值,之后每一次while循環(huán),diceRoll的值使用前置自增操作符(++i)來自增 1 ,然后檢測是否超出了最大值。++diceRoll調(diào)用完成,返回值等于diceRoll自增后的值。任何時(shí)候如果diceRoll的值等于7時(shí),就超過了骰子的最大值,會(huì)被重置為1。所以diceRoll的取值順序會(huì)一直是1,23,4,56,1,2

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

如果沒有這個(gè)檢測(square < board.count),board[square]可能會(huì)越界訪問board數(shù)組,導(dǎo)致錯(cuò)誤。例如如果square等于26, 代碼會(huì)去嘗試訪問board[26],超過數(shù)組的長度。

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

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

Do-While

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

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

do {
statements
} while condition

還是蛇和梯子的游戲,使用do-while循環(huán)來替代while循環(huán)。finalSquareboard、squarediceRoll的值初始化同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

do-while的循環(huán)版本,循環(huán)中_第一步_就需要去檢測是否在梯子或者蛇的方塊上。沒有梯子會(huì)讓玩家直接上到第 25 個(gè)方格,所以玩家不會(huì)通過梯子直接贏得游戲。這樣在循環(huán)開始時(shí)先檢測是否踩在梯子或者蛇上是安全的。

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

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

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

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

條件語句

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

Swift 提供兩種類型的條件語句:if語句和switch語句。通常,當(dāng)條件較為簡單且可能的情況很少時(shí),使用if語句。而switch語句更適用于條件較復(fù)雜、可能情況較多且需要用到模式匹配(pattern-matching)的情境。

If

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

    var temperatureInFahrenheit = 30
    if temperatureInFahrenheit <= 32 {
        println("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語句允許二選一,也就是當(dāng)條件為false時(shí),執(zhí)行 else 語句

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

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

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

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

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

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

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

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

Switch

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

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

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語句都由多個(gè) case 構(gòu)成。為了匹配某些更特定的值,Swift 提供了幾種更復(fù)雜的匹配模式,這些模式將在本節(jié)的稍后部分提到。

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

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

下面的例子使用switch語句來匹配一個(gè)名為someCharacter的小寫字符:

    let someCharacter: Character = "e"
    switch someCharacter {
    case "a", "e", "i", "o", "u":
        println("\(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":
        println("\(someCharacter) is a consonant")
    default:
        println("\(someCharacter) is not a vowel or a consonant")
    }
    // 輸出 "e is a vowel"

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

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

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

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

注意:
你依然可以在 case 分支中的代碼執(zhí)行完畢前跳出,詳情請參考Switch 語句中的 break。

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

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

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

一個(gè) case 也可以包含多個(gè)模式,用逗號(hào)把它們分開(如果太長了也可以分行寫):

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

注意:
如果想要貫穿至特定的 case 分支中,請使用fallthrough語句,詳情請參考貫穿(Fallthrough)。

區(qū)間匹配(Range Matching)

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

    let count = 3_000_000_000_000
    let countedThings = "stars in the Milky Way"
    var naturalCount: String
    switch count {
    case 0:
        naturalCount = "no"
    case 1...3:
        naturalCount = "a few"
    case 4...9:
        naturalCount = "several"
    case 10...99:
        naturalCount = "tens of"
    case 100...999:
        naturalCount = "hundreds of"
    case 1000...999_999:
        naturalCount = "thousands of"
    default:
        naturalCount = "millions and millions of"
    }
    println("There are \(naturalCount) \(countedThings).")
    // 輸出 "There are millions and millions of stars in the Milky Way."

元組(Tuple)

你可以使用元組在同一個(gè)switch語句中測試多個(gè)值。元組中的元素可以是值,也可以是區(qū)間。另外,使用下劃線(_)來匹配所有可能的值。

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

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

http://wiki.jikexueyuan.com/project/swift-language-guide/images/Control_Flow_2.png" alt="Image of Control_Flow_2.png" />

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

不像 C 語言,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 分支里就可以被引用了——這種行為被稱為值綁定(value binding)。

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

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

http://wiki.jikexueyuan.com/project/swift-language-guide/images/Control_Flow_3.png" alt="Image of Control_Flow_3.png" />

在上面的例子中,switch語句會(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。類似的,第二個(gè) case ——case (0, let y)將匹配一個(gè)橫坐標(biāo)為0的點(diǎn),并把這個(gè)點(diǎn)的縱坐標(biāo)賦給臨時(shí)的常量y

一旦聲明了這些臨時(shí)的常量,它們就可以在其對應(yīng)的 case 分支里引用。在這個(gè)例子中,它們用于簡化println的書寫。

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

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

Where

case 分支的模式可以使用where語句來判斷額外的條件。

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

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

http://wiki.jikexueyuan.com/project/swift-language-guide/images/Control_Flow_4.png" alt="Image of Control_Flow_4.png" />

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

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

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

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

控制轉(zhuǎn)移語句改變你代碼的執(zhí)行順序,通過它你可以實(shí)現(xiàn)代碼的跳轉(zhuǎn)。Swift有四種控制轉(zhuǎn)移語句。

  • continue
  • break
  • fallthrough
  • return

我們將會(huì)在下面討論continue、breakfallthrough語句。return語句將會(huì)在函數(shù)章節(jié)討論。

Continue

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

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

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

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

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

Break

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

循環(huán)語句中的 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 語句中的 break

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

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

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

下面的例子通過switch來判斷一個(gè)Character值是否代表下面四種語言之一。為了簡潔,多個(gè)值被包含在了同一個(gè)分支情況中。

    let numberSymbol: Character = "三"  // 簡體中文里的數(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 {
        println("The integer value of \(numberSymbol) is \(integerValue).")
    } else {
        println("An integer value could not be found for \(numberSymbol).")
    }
    // 輸出 "The integer value of 三 is 3."

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

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

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

貫穿(Fallthrough)

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

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

    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."
    }
    println(description)
    // 輸出 "The number 5 is a prime number, and also an integer."

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

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

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

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

帶標(biāo)簽的語句(Labeled Statements)

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

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

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

label name: while condition {
statements
}

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

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

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

游戲的棋盤和之前一樣:

http://wiki.jikexueyuan.com/project/swift-language-guide/images/Control_Flow_5.png" alt="Image of Control_Flow_5.png" />

finalSquareboard、squarediceRoll的初始化也和之前一樣:

    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方法塊來實(shí)現(xiàn)游戲的邏輯。while循環(huán)體有一個(gè)標(biāo)簽名gameLoop,來表明它是蛇與梯子的主循環(huán)。

while循環(huán)體的條件判斷語句是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]
        }
    }
    println("Game over!")

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

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

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

上一篇:泛型下一篇:高級運(yùn)算符