控制流

For循環

for循環用來按照指定的次數多次執行一系列語句。Swift 提供兩種for循環形式:

  • for-in用來遍歷一個區間(range),序列(sequence),集合(collection),系列(progression)里面所有的元素執行一系列語句。
    1.區間
    <pre><code>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
    </code></pre>

2.區間(忽略對值的訪問)
<pre><code>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"
</code></pre>

這個計算并不需要知道每一次循環中計數器具體的值,只需要執行了正確的循環次數即可。下劃線符號_(替代循環中的變量)能夠忽略具體的值,并且不提供循環遍歷時對值的訪問。
3.遍歷數組

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

4.遍歷字典

<pre><code>
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
</code></pre>

字典元素的遍歷順序和插入順序可能不同,字典的內容在內部是無序的,所以遍歷元素時不能保證順序。

5.遍歷字符

<pre><code>for character in "Hello" {
println(character)
}
// H
// e
// l
// l
// o
</code></pre>

  • for條件遞增(for-condition-increment)語句,用來重復執行一系列語句直到達成特定條件達成,一般通過在每次循環完成后增加計數器的值來實現。
    1.for initialization; condition; increment { statements }
    <pre><code>for var index = 0; index < 3; ++index {
    println("index is (index)")
    }
    // index is 0
    // index is 1
    // index is 2
    </code></pre>

Switch

switch語句會嘗試把某個值與若干個模式(pattern)進行匹配。根據第一個匹配成功的模式,switch語句會執行對應的代碼。當有可能的情況較多時,通常用switch語句替換if語句。

  • 正常switch
    <pre><code>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"
    </code></pre>一個 case 也可以包含多個模式,用逗號把它們分開(如果太長了也可以分行寫)
    <pre><code>switch some value to consider { case value 1, value 2: statements }</code></pre>

不存在隱式的貫穿(No Implicit Fallthrough)
在 Swift 中,當匹配的 case 分支中的代碼執行完畢后,程序會終止switch語句,而不會繼續執行下一個 case 分支。不需要在 case 分支中顯式地使用break語句

  • 區間匹配(Range Matching)
    case 分支的模式也可以是一個值的區間。下面的例子展示了如何使用區間匹配來輸出任意數字對應的自然語言格式:
    <pre><code>
    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."</code></pre>

  • 匹配元組(Tuple)
    你可以使用元組在同一個switch語句中測試多個值。元組中的元素可以是值,也可以是區間。另外,使用下劃線()來匹配所有可能的值。
    <pre><code>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"</code></pre>

  • 值綁定(Value Bindings)
    case 分支的模式允許將匹配的值綁定到一個臨時的常量或變量,這些常量或變量在該 case 分支里就可以被引用了——這種行為被稱為值綁定(value binding)。

<pre><code>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"</code></pre>

  • Where語句
    case 分支的模式可以使用where語句來判斷額外的條件。
    <pre><code>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"</code></pre>

控制轉移語句(Control Transfer Statements)

控制轉移語句改變你代碼的執行順序,通過它你可以實現代碼的跳轉。Swift有四種控制轉移語句。

  • continue

continue語句告訴一個循環體立刻停止本次循環迭代,重新開始下次循環迭代。就好像在說“本次循環迭代我已經執行完了”,但是并不會離開整個循環體。

注意:

在一個for條件遞增(for-condition-increment)循環體中,在調用continue語句后,迭代增量仍然會被計算求值。循環體繼續像往常一樣工作,僅僅只是循環體中的執行代碼會被跳過。
<pre><code>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"</code></pre>

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

  • break

break語句會立刻結束整個控制流的執行。當你想要更早的結束一個switch代碼塊或者一個循環體時,你都可以使用break語句。

1.循環語句中的 break

當在一個循環體中使用break時,會立刻中斷該循環體的執行,然后跳轉到表示循環體結束的大括號(})后的第一行代碼。不會再有本次循環迭代的代碼被執行,也不會再有下次的循環迭代產生。

2.Switch 語句中的 break

當在一個switch代碼塊中使用break時,會立即中斷該switch代碼塊的執行,并且跳轉到表示switch代碼塊結束的大括號(})后的第一行代碼

  • fallthrough

Swift 中的switch不會從上一個 case 分支落入到下一個 case 分支中。相反,只要第一個匹配到的 case 分支完成了它需要執行的語句,整個switch代碼塊完成了它的執行

如果你確實需要 C 風格的貫穿(fallthrough)的特性,你可以在每個需要該特性的 case 分支中使用fallthrough關鍵字
<pre><code>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."</code></pre>

注意:

fallthrough關鍵字不會檢查它下一個將會落入執行的 case 中的匹配條件。fallthrough簡單地使代碼執行繼續連接到下一個case 中的執行代碼,這和 C 語言標準中的switch語句特性是一樣的。

  • 帶標簽的語句(Labeled Statements)

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

為了實現這個目的,你可以使用標簽來標記一個循環體或者switch代碼塊,當使用break或者continue時,帶上這個標簽,可以控制該標簽代表對象的中斷或者執行。

產生一個帶標簽的語句是通過在該語句的關鍵詞的同一行前面放置一個標簽,并且該標簽后面還需帶著一個冒號。下面是一個while循環體的語法,同樣的規則適用于所有的循環體和switch代碼塊。

<pre><code>label name: while condition { statements }</code></pre>

下面的例子是在一個帶有標簽的while循環體中調用breakcontinue語句,該循環體是前面章節中蛇和梯子的改編版本。這次,游戲增加了一條額外的規則:
為了獲勝,你必須剛好落在第 25 個方塊中。
如果某次擲骰子使你的移動超出第 25 個方塊,你必須重新擲骰子,直到你擲出的骰子數剛好使你能落在第 25 個方塊中。
<pre><code>
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</code></pre>

這個版本的游戲使用while循環體和switch方法塊來實現游戲的邏輯。while循環體有一個標簽名gameLoop,來表明它是蛇與梯子的主循環。

while循環體的條件判斷語句是while square !=finalSquare,這表明你必須剛好落在方格25中。

<pre><code>
gameLoop: while square != finalSquare {
if ++diceRoll == 7 { diceRoll = 1 }
switch square + diceRoll {
case finalSquare:
// 到達最后一個方塊,游戲結束
break gameLoop
case let newSquare where newSquare > finalSquare:
// 超出最后一個方塊,再擲一次骰子
continue gameLoop
default:
// 本次移動有效
square += diceRoll
square += board[square]
}
}
println("Game over!")</code></pre>

每次循環迭代開始時擲骰子。與之前玩家擲完骰子就立即移動不同,這里使用了switch來考慮每次移動可能產生的結果,從而決定玩家本次是否能夠移動。

1.如果骰子數剛好使玩家移動到最終的方格里,游戲結束。break gameLoop語句跳轉控制去執行while循環體后的第一行代碼,游戲結束。
2.如果骰子數將會使玩家的移動超出最后的方格,那么這種移動是不合法的,玩家需要重新擲骰子。continue gameLoop語句結束本次while循環的迭代,開始下一次循環迭代。
3.在剩余的所有情況中,骰子數產生的都是合法的移動。玩家向前移動骰子數個方格,然后游戲邏輯再處理玩家當前是否處于蛇頭或者梯子的底部。本次循環迭代結束,控制跳轉到while循環體的條件判斷語句處,再決定是否能夠繼續執行下次循環迭代。

注意:

如果上述的break語句沒有使用gameLoop標簽,那么它將會中斷switch代碼塊而不是while循環體。使用gameLoop標簽清晰的表明了break想要中斷的是哪個代碼塊。 同時請注意,當調用continue gameLoop去跳轉到下一次循環迭代時,這里使用gameLoop標簽并不是嚴格必須的。因為在這個游戲中,只有一個循環體,所以continue語句會影響到哪個循環體是沒有歧義的。然而,continue語句使用gameLoop標簽也是沒有危害的。這樣做符合標簽的使用規則,同時參照旁邊的break gameLoop,能夠使游戲的邏輯更加清晰和易于理解。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容