swift學習筆記(5)-控制流

For-In 循環

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

如果你不需要區間序列內每一項的值,你可以使用下劃線(_)替代變量名來忽略這個值:

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"

在for-in循環中使用顯式的常量名稱來解讀(key, value)元組。

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

while循環

while condition {  
    statements
}
repeat {
    statements
} while condition

和oc的do-while一樣的

if條件語句

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."

Switch

switch語句必須是完備的。這就是說,每一個可能的值都必須至少有一個 case 分支與之對應。在某些不可能涵蓋所有值的情況下,你可以使用默認(default)分支來涵蓋其它所有沒有對應的值,這個默認分支必須在switch語句的最後面。
不存在隱式的貫穿

與 C 和 Objective-C 中的switch語句不同,在 Swift 中,當匹配的 case 分支中的代碼執行完畢後,程序會終止switch語句,而不會繼續執行下一個 case 分支。這也就是說,不需要在 case 分支中顯式地使用break語句。這使得switch語句更安全、更易用,也避免了因忘記寫break語句而產生的錯誤。但是break仍然可用。

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // 無效,這個分支下面沒有語句
case "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// 這段代碼會報編譯錯誤

不像 C 語言裏的switch語句,在 Swift 中,switch語句不會一起匹配”a”和”A”。相反的,上面的代碼會引起編譯期錯誤:case “a”: 不包含任何可執行語句——這就避免了意外地從一個 case 分支貫穿到另外一個,使得代碼更安全、也更直觀。

爲了讓單個case同時匹配a和A,可以將這個兩個值組合成一個複合匹配,並且用逗號分開:

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// 輸出 "The letter A

區間匹配

case 分支的模式也可以是一個值的區間。下面的例子展示瞭如何使用區間匹配來輸出任意數字對應的自然語言格式:

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."

元組

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

下面的例子展示瞭如何使用一個(Int, Int)類型的元組來分類下圖中的點(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"

值綁定

case 分支允許將匹配的值綁定到一個臨時的常量或變量,並且在case分支體內使用 —— 這種行爲被稱爲值綁定,因爲匹配的值在case分支體內,與臨時的常量或變量綁定。

下面的例子展示瞭如何在一個(Int, Int)類型的元組中使用值綁定來分類下圖中的點(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"

Where

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

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"

控制轉移語句

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

  • continue
  • break
  • fallthrough
  • return
  • throw

貫穿

Swift 中的switch不會從上一個 case 分支落入到下一個 case 分支中。相反,只要第一個匹配到的 case 分支完成了它需要執行的語句,整個switch代碼塊完成了它的執行。
如果你確實需要 C 風格的貫穿的特性,你可以在每個需要該特性的 case 分支中使用fallthrough關鍵字。下面的例子使用fallthrough來創建一個數字的描述語句。

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."

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

帶標籤的語句

label name: while condition { statements }
gameLoop: while square != finalSquare {
    diceRoll += 1
    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]
    }
}
print("Game over!")

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

提前退出

像if語句一樣,guard的執行取決於一個表達式的布爾值。我們可以使用guard語句來要求條件必須爲真時,以執行guard語句後的代碼。不同於if語句,一個guard語句總是有一個else從句,如果條件不爲真則執行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"])
// 輸出 "Hello John!"
// 輸出 "I hope the weather is nice near you."
greet(["name": "Jane", "location": "Cupertino"])
// 輸出 "Hello Jane!"
// 輸出 "I hope the weather is nice in Cupertino."

如果條件不被滿足,在else分支上的代碼就會被執行。這個分支必須轉移控制以退出guard語句出現的代碼段。它可以用控制轉移語句如return,break,continue或者throw做這件事,或者調用一個不返回的方法或函數,例如fatalError()。

檢測 API 可用性

我們在if或guard語句中使用可用性條件(availability condition)去有條件的執行一段代碼,來在運行時判斷調用的API是否可用。編譯器使用從可用性條件語句中獲取的信息去驗證,在這個代碼塊中調用的 API 是否可用。

if #available(iOS 10, macOS 10.12, *) {
    // 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API
} else {
    // 使用先前版本的 iOS 和 macOS 的 API
}

以上可用性條件指定,在iOS中,if語句的代碼塊僅僅在 iOS 10 及更高的系統下運行;在 macOS中,僅在 macOS 10.12 及更高才會運行。最後一個參數,*,是必須的,用於指定在所有其它平臺中,如果版本號高於你的設備指定的最低版本,if語句的代碼塊將會運行。

在它一般的形式中,可用性條件使用了一個平臺名字和版本的列表。平臺名字可以是iOS,macOS,watchOS和tvOS——請訪問聲明屬性來獲取完整列表。除了指定像 iOS 8的主板本號,我們可以指定像iOS 8.3 以及 macOS 10.10.3的子版本號。

if #available(platform name version, ..., *) {
    APIs 可用,語句將執行
} else {
    APIs 不可用,語句將不執行
}
發佈了23 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章