Swift控制流_5

Swift提供了多種流程控制結構,包括可以多次執行任務的while循環,基于特定條件基于特定條件選擇執行不同代碼分支的ifguardswitch語句,還有控制流程跳轉到其他代碼位置的breakcontinue語句 Swift還提供了for-in循環,用來更簡單的遍歷數組 (Array),字典(Dictionary),集合(Set),區間 (Range),字符串 (String)和其他序列類型 Swift的switch語句比c語言中更加強大,case還可以匹配很多不同的模式,包括范圍匹配,元組和特定類型匹配,switch語句的case中匹配的值可以聲明為臨時常量或變量,在case作用域內使用,也可以匹配where`來描述更復雜的匹配條件

For-in
//遍歷數組
let arr1 = ["i","am","a","good","boy"]
for arr1Str in arr1 {
    print("arr1Str:\(arr1Str)")
}
/*
 arr1Str:i
 arr1Str:am
 arr1Str:a
 arr1Str:good
 arr1Str:boy
 */

//遍歷集合
let set1:Set = [1,2,3,4,5]
for set1Int in set1 {
    print("set1Int:\(set1Int)")
}
/*
 set1Int:5
 set1Int:2
 set1Int:3
 set1Int:1
 set1Int:4
 */

//遍歷字典
let dic1 = [1:"1",2:"2",3:"3"]
for (dicKey,dicValue) in dic1 {
    print("dicKey:\(dicKey) dicValue:\(dicValue)")
}
/*
 dicKey:2 dicValue:2
 dicKey:3 dicValue:3
 dicKey:1 dicValue:1
 */

//遍歷字符串
let str1 = "iamagoodboy"
for str1Ch in str1 {
    print("str1Ch:\(str1Ch)")
}
/*
 str1Ch:i
 str1Ch:a
 str1Ch:m
 str1Ch:a
 str1Ch:g
 str1Ch:o
 str1Ch:o
 str1Ch:d
 str1Ch:b
 str1Ch:o
 str1Ch:y
*/

//循環數字范圍
for idx in 1...5 {
    print("\(idx) times 5 is \(idx*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
 */
While

while循環會一直運行一段語句直到條件變成false

條件只能為truefalse,oc中只要為正數也可能表示條件為true,swift中不行
這類循環適合使用在第一次迭代前,迭代次數未知的情況下。Swift 提供兩種while循環形式

  • while循環,每次在循環開始時計算條件是否符合
var whileI:Int = 10
while whileI > 0 {
    print("whileI:\(whileI)")
    whileI -= 1
    //--whileI 在swift廢除了?????
}
/*
 whileI:10
 whileI:9
 whileI:8
 whileI:7
 whileI:6
 whileI:5
 whileI:4
 whileI:3
 whileI:2
 whileI:1
 */
  • repeat-while循環,每次在循環結束時計算條件是否符合,意思就是說:它和while的區別是在判斷循環條件之前,先執行一次循環的代碼塊。然后重復循環直到條件為false,可以相當于oc中的do-while
//Repeat-While

var whilerR = false
repeat{
    print("whilerR")
}while whilerR
/*
 whilerR 
 先進去statements再判斷下次是否進入
 */
if

if語句是最簡單的形式,只包含一個條件,只有該條件為true,才執行相關代碼

注意,跟while的條件判斷是一樣,swift下的條件判斷只有truefalse,正整數并不能表示true

Switch

oc中的switch的參數類型要求是integer type,如果不是integer就會報錯Statement requires expression of integer type ('NSString *__strong' invalid)
oc中的case 語句是為了匹配switch中的參數的值,所以其條件值必須是常數(const)

image.png

下面來說了swift中的switch

let switchT1 = 1
switch switchT1 {
case 1:
    print("switchT1 == 1")
default:
    print("switchT1 != 1")
}
/*
switchT1 == 1
*/

let someCharacter: Character = "z"
switch someCharacter {
case "a":
    print("The first letter of the alphabet")
case "z":
    print("The last letter of the alphabet")
default:
    print("Some other character")
}
/*
 The last letter of the alphabet
 */
  • CObjective-C 中的switch語句不同,在 Swift 中,當匹配的 case 分支中的代碼執行完畢后,程序會終止switch語句,而不會繼續執行下一個 case 分支。這也就是說,不需要在 case 分支中顯式地使用break語句。這使得switch語句更安全、更易用,也避免了因忘記寫break語句而產生的錯誤

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

  • 每一個 case 分支都必須包含至少一條語句。像下面這樣書寫代碼是無效的,因為第一個 case 分支是空的
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同時匹配aA,可以將這個兩個值組合成一個復合匹配,并且用逗號分開

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"
let 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("\(somePoint) is at the origin")
case (_, 0):
    print("\(somePoint) is on the x-axis")
case (0, _):
    print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
    print("\(somePoint) is inside the box")
default:
    print("\(somePoint) is outside of the box")
}
// 輸出 "(1, 1) is inside the box"
continue

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

break

break語句會立刻結束整個控制流的執行

  • 循環語句中的 break
    當在一個循環體中使用break時,會立刻中斷該循環體的執行,然后跳轉到表示循環體結束的大括號(})后的第一行代碼。不會再有本次循環的代碼被執行,也不會再有下次的循環產生
  • Switch 語句中的 break
    當在一個switch代碼塊中使用break時,會立即中斷該switch代碼塊的執行,并且跳轉到表示switch代碼塊結束的大括號(})后的第一行代碼
fallthrough 貫穿

在 Swift 里,switch語句不會從上一個 case 分支跳轉到下一個 case分支中。相反,只要第一個匹配到的 case 分支完成了它需要執行的語句,整個switch代碼塊完成了它的執行。相比之下,C 語言要求你顯式地插入break語句到每個 case 分支的末尾來阻止自動落入到下一個 case 分支中。Swift的這種避免默認落入到下一個分支中的特性意味著它的switch 功能要比 C 語言的更加清晰和可預測,可以避免無意識地執行多個 case 分支從而引發的錯誤。

如果你確實需要 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."

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

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

switch代碼塊執行完后,使用print(_:separator:terminator:)函數打印該數字的描述。在這個例子中,數字5被準確的識別為了一個質數

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

帶標簽的語句

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

為了實現這個目的,你可以使用標簽(statement label)來標記一個循環體或者條件語句,對于一個條件語句,你可以使用break加標簽的方式,來結束這個被標記的語句。對于一個循環語句,你可以使用break或者continue加標簽,來結束或者繼續這條被標記語句的執行。

聲明一個帶標簽的語句是通過在該語句的關鍵詞的同一行前面放置一個標簽,作為這個語句的前導關鍵字(introducor keyword),并且該標簽后面跟隨一個冒號。下面是一個針對while循環體的標簽語法,同樣的規則適用于所有的循環體和條件語句

label name: while condition { statements }
提前退出

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

如果guard語句的條件被滿足,則繼續執行guard語句大括號后的代碼。將變量或者常量的可選綁定作為guard語句的條件,都可以保護guard語句后面的代碼。

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

相比于可以實現同樣功能的if語句,按需使用guard語句會提升我們代碼的可讀性。它可以使你的代碼連貫的被執行而不需要將它包在else塊中,它可以使你在緊鄰條件判斷的地方,處理違規的情況

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

推薦閱讀更多精彩內容