Swift提供了類似C語言的流程控制結構,包括可以多次執行任務的for和while循環,基于特定條件選擇執行不同代碼分支的if和switch語句,還有控制流程跳轉到其他代碼的break和continue語句。
Swift 的 switch 語句比 C 語言中更加強大。在 C 語言中,如果某個 case 不小心漏寫了 break,這個 case 就會“掉入”下一個 case,Swift 無需寫 break,是以不會發生這種“掉入”的情況。Case 還可以比對更多的類型模式,包括範圍(range)比對,元組(tuple)和特定類型的描述。switch case 語句中比對的值可以是由 case 體内部臨時的常量或者變量決定,也可以由 where 分句描述更複雜的比對條件。
一、for和for-in循環
for index in 1...5 {
println("\(index) times 5 is \(index*5)")
}
上面的例子中,index 是一個每次循環周遊開始時被自動指派的常量。這種情況下,index 在使用前不需要聲明,隻需要将它包含在循環的聲明中,就可以對其進行隐式聲明,而無需使用 let 關鍵字聲明。
注意:index 常量隻存在于循環的生命周期裡。如果你想在循環完成後通路 index 的值,又或者想讓 index 成為一個變量而不是常量,你必須在循環之前自己進行聲明。
如果你不需要知道範圍内每一項的值,你可以使用下劃線(_)替代變量名來忽略對值的通路:
let base = 3
let power = 10
var answer = 1
for _ in 1...power{ //範圍文法非常簡潔
answer *= base
}
println("\(base) to the power of \(power) is \(answer)")
//周遊數組
let names = ["Anna","Alex","Brian","Jack"]
for name in names{
println("Hello,\(name)!")
}
//周遊字典
let numberOfLegs = ["Spider":8,"Ant":6,"Cat":4]
for (animalName,legCount) in numberOfLegs{
println("\(animalName)s have \(legCount) legs")
}
//周遊字元串中的字元
for character in "Hello"{
println(character)
}
//for循環
for var index = 0;index < 3;index++ {
println("index is \(index)")
}
Swift中的while循環、if語句跟OC和其他語言中的寫法差別不大,唯一的差別就是不需要寫那麼多圓括号,這裡不介紹了。
二、switch語句
let someCharacter:Character = "e"
switch someCharacter{
case "a","e","i","o","u":
println("\(someCharacter) is a vowel.")
case "b","c","d","f","g","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.")
}
switch語句必須是完備的。這就是說,每一個可能的值都必須至少有一個case塊與之對應。在某些不可能涵蓋所有值的情況下,你可以使用預設(default)塊滿足該要求,這個預設塊必須在switch語句的最後面。
switch語句特點:
1、不存在隐式的貫穿(Fallthrough)
與C語言和Objective-C中的switch語句不同,在 Swift 中,當比對的case塊中的代碼執行完畢後,程式會終止switch語句,而不會繼續執行下一個case塊。這也就是說,不需要在case塊中顯式地使用break語句。這使得switch語句更安全、更易用,也避免了因忘記寫break語句而産生的錯誤。
注意:你依然可以在case塊中的代碼執行完畢前跳出。
每一個case塊都必須包含至少一條語句。像下面這樣書寫代碼是無效的,因為第一個case塊是空的:
let anotherCharacter:Character = "a"
switch anotherCharacter{
case "a":
case "A":
println("The letter A")
default:
println("Not the letter A")
}
不像C語言裡的switch語句,在 Swift 中,switch語句不會同時比對"a"和"A"。相反的,上面的代碼會引起編譯期錯誤:case "a": does not contain any executable statements——這就避免了意外地從一個case塊貫穿到另外一個,使得代碼更安全、也更直覺。
一個case也可以包含多個模式,用逗号把它們分開。
2、範圍比對
case塊的模式也可以是一個值的範圍。下面的例子展示了如何使用範圍比對來輸出任意數字對應的自然語言格式:
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).")
3、元組比對
你可以使用元組在同一個switch語句中測試多個值。元組中的元素可以是值,也可以是範圍。另外,使用下劃線(_)來比對所有可能的值。
let somePoint = (1,1) //試試(0,0)
switch somePoint{
case (0,0):
println("(0,0) is at the orign")
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 the box")
}
在上面的例子中,switch語句會判斷某個點是否是原點(0, 0),是否在紅色的x軸上,是否在黃色y軸上,是否在一個以原點為中心的4x4的矩形裡,或者在這個矩形外面。
不像C語言,Swift 允許多個case比對同一個值。實際上,在這個例子中,點(0, 0)可以比對所有四個case。但是,如果存在多個比對,那麼隻會執行第一個被比對到的case塊。考慮點(0, 0)會首先比對case (0, 0),是以剩下的能夠比對(0, 0)的case塊都會被忽視掉。
4、值綁定
case塊的模式允許将比對的值綁定到一個臨時的常量或變量,這些常量或變量在該case塊裡就可以被引用了——這種行為被稱為值綁定。
let anotherPoint = (2,0)
switch anotherPoint{
case (let x,0):
println("on the x-axis with a 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))")
}
一旦聲明了這些臨時的常量,它們就可以在其對應的case塊裡引用。在這個例子中,它們用于簡化println的書寫。
請注意,這個switch語句不包含預設塊。這是因為最後一個case——case let(x, y)聲明了一個可以比對餘下所有值的元組。這使得switch語句已經完備了,是以不需要再書寫預設塊。
在上面的例子中,x和y是常量,這是因為沒有必要在其對應的case塊中修改它們的值。然而,它們也可以是變量——程式将會建立臨時變量,并用相應的值初始化它。修改這些變量隻會影響其對應的case塊。
5、where關鍵字
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")
}
在上面的例子中,switch語句會判斷某個點是否在綠色的對角線x == y上,是否在紫色的對角線x == -y上,或者不在對角線上。
這三個case都聲明了常量x和y的占位符,用于臨時擷取元組yetAnotherPoint的兩個值。這些常量被用作where語句的一部分,進而建立一個動态的過濾器(filter)。當且僅當where語句的條件為真時,比對到的case塊才會被執行。
就像是值綁定中的例子,由于最後一個case塊比對了餘下所有可能的值,switch語句就已經完備了,是以不需要再書寫預設塊。
三、控制轉移語句
Swift中有四種控制轉移語句:continue、break、fallthrough和return
1、 continue
continue告訴一個循環體立刻停止本次循環疊代,重新開始下次循環疊代。就好像在說“本次循環疊代我已經執行完了”,但是并不會離開整個循環體。
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)
}
}
2、break
在循環體中使用Break
當在一個循環體中使用break時,會立刻中斷該循環體的執行,然後跳轉到表示循環體結束的大括号(})後的第一行代碼。不會再有本次循環疊代的代碼被執行,也不會再有下次的循環疊代産生。
在Switch代碼塊中使用Break
當在一個switch代碼塊中使用break時,會立即中斷該switch代碼塊的執行,并且跳轉到表示switch代碼塊結束的大括号(})後的第一行代碼。
這種特性可以被用來比對或者忽略一個或多個分支。因為Swift語言的switch需要包含所有的分支而且不允許有為空的分支,有時為了使你的意圖更明顯,需要特意比對或者忽略某個分支。那麼當你想忽略某個分支時,可以在該分支内寫上break語句。當那個分支被比對到時,分支内的break語句立即結束switch代碼塊。
3、fallthrough
Swift語言中的switch不會從上一個case分支落入到下一個case分支中。相反,隻要第一個比對到的case分支完成了它需要執行的語句,整個switch代碼塊完成了它的執行。相比之下,C語言要求你顯示的插入break語句到每個switch分支的末尾來阻止自動落入到下一個case分支中。Swift語言的這種避免預設落入到下一個分支中的特性意味着它的switch 功能要比C語言的更加清晰和可預測,可以避免無意識地執行多個case分支進而引發的錯誤。
如果你确實需要C風格的落入(fallthrough)的特性,你可以在每個需要該特性的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."
}
println(description)
// prints "The number 5 is a prime number, and also an integer."
注意:fallthrough關鍵字不會檢查它下一個将會落入執行的case中的比對條件。fallthrough簡單地使代碼執行繼續連接配接到下一個case中的執行代碼,這和C語言标準中的switch語句特性是一樣的。
四、标記文法 (Labeled Statements)
在Swift語言中,你可以在循環體和switch代碼塊中嵌套循環體和switch代碼塊來創造複雜的控制流結構。然而,循環體和switch代碼塊兩者都可以使用break語句來提前結束整個方法體。是以,顯示地指明break語句想要終止的是哪個循環體或者switch代碼塊,會很有用。類似地,如果你有許多嵌套的循環體,顯示指明continue語句想要影響哪一個循環體也會非常有用。
為了實作這個目的,你可以使用标簽來标記一個循環體或者switch代碼塊,當使用break或者continue時,帶上這個标簽,可以控制該标簽代表對象的中斷或者執行。
産生一個帶标簽的語句是通過在該語句的關鍵詞的同一行前面放置一個标簽,并且該标簽後面還需帶着一個冒号。下面是一個while循環體的文法,同樣的規則适用于所有的循環體和switch代碼塊。
label name: while condition {
statements
}
例:
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
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!")
注意:如果上述的break語句沒有使用gameLoop标簽,那麼它将會中斷switch代碼塊而不是while循環體。使用gameLoop标簽清晰的表明了break想要中斷的是哪個代碼塊。 同時請注意,當調用continue gameLoop去跳轉到下一次循環疊代時,這裡使用gameLoop标簽并不是嚴格必須的。因為在這個遊戲中,隻有一個循環體,是以continue語句會影響到哪個循環體是沒有歧義的。然而,continue語句使用gameLoop标簽也是沒有危害的。這樣做符合标簽的使用規則,同時參照旁邊的break gameLoop,能夠使遊戲的邏輯更加清晰和易于了解。
總結:
本章介紹了Swift語言的控制流,循環和分支語句,重點是switch分支文法的變化,以及它的特性,還有标記文法。Swift的控制流文法跟OC有很多相似之處,特别是for循環和for-in循環、if語句、while和do-while語句都跟OC類似。差别最大的就是switch的控制流文法以及标記文法。下面總結幾個重點:
1、神奇的下劃線(_) :在for-in循環中, 如果你不需要知道範圍内每一項的值,你可以使用_替代變量名來忽略對值的通路。在switch文法中,_可以做任何值的占位符。
2、Swift的switch控制流不存在隐式貫穿,這樣每個case後面可以不寫break關鍵字,它不會像OC中或者C中那樣預設會從一個case落入下一個case中,一旦比對一個case預設就不會繼續比對其他case,更加安全易用。
3、Swift的switch控制流必須是完備的,如果switch中的幾個case可以包含所有的情況,就可以不寫default分支,否則必須寫default分支,這樣就不僅提高了代碼的可讀性,也非常的安全。Swift語言的神奇之處是它可以檢查你寫的幾個case是否包含了所有情況,如果是,你不寫default分支就不會報錯,否則就會報錯。
4、Swift的switch控制流中一個case可以包含多個模式,用逗号隔開。switch不允許空的case,可以使用break來解決。
5、Swift的switch控制流中可以比對多種資料,比如範圍和元組。
6、Swift的switch控制流中可以使用值綁定,非常友善的拿到周遊的值來臨時操作。
7、Swift的switch控制流中可以使用where關鍵字來加額外的比對條件,像SQL語句一樣神奇,易讀性也非常高。where常和值綁定一起使用。
8、Swift的switch控制流要想達到像C那樣的自動從一個case落入下一個case,可以使用fallthrough關鍵字。
9、因為Swift的switch控制流的不存在隐式貫穿的特點,Swift引入了标記文法。在循環和switch結合使用的時候,可以通過給循環和switch加上标記,進而在需要break和continue的地方通過這個标記來明确告訴編譯器要結束或者繼續某個循環或者switch。
參考:
1.The Swift Programming Language
2.http://www.cocoachina.com/ios/20140611/8769.html