Swift-控制流(二)

Swift提供了各種控制流語句。 這些包括while循環(huán)來執(zhí)行多次任務(wù); if,guard和switch語句,以根據(jù)特定條件執(zhí)行不同的代碼分支; 和諸如斷點(diǎn)之類的語句,并繼續(xù)將執(zhí)行流程傳遞到代碼中的另一個(gè)點(diǎn)。

Swift還提供了一個(gè)for-in循環(huán),使得可以輕松地遍歷數(shù)組,字典,范圍,字符串和其他序列。

Swift的switch語句也比許多C語言的語言更強(qiáng)大。 因?yàn)閟witch語句的情況不會(huì)落入到Swift中的下一個(gè)情況,所以它避免了由于缺少break語句而導(dǎo)致的常見C錯(cuò)誤。 情況可以匹配許多不同的模式,包括間隔匹配,元組和轉(zhuǎn)換到特定類型。 開關(guān)情況下的匹配值可以綁定到臨時(shí)常量或變量以在案例主體中使用,并且復(fù)雜匹配條件可以用每個(gè)案例的where子句表示。

for-in循環(huán)

您可以使用for-in循環(huán)對(duì)序列進(jìn)行迭代,例如數(shù)字范圍,數(shù)組中的項(xiàng)或字符串中的字符。

此示例打印五次表中的前幾個(gè)條目:

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

被迭代的序列是從1到5的數(shù)字范圍,包括1和5,如使用閉合范圍運(yùn)算符(...)所指示的。 index的值設(shè)置為范圍(1)中的第一個(gè)數(shù),并執(zhí)行循環(huán)內(nèi)的語句。 在這種情況下,循環(huán)只包含一個(gè)語句,它從五次表中為索引的當(dāng)前值打印一個(gè)條目。 語句執(zhí)行后,index的值被更新為包含范圍(2)中的第二個(gè)值,并再次調(diào)用print(_:separator:terminator :)函數(shù)。 該過程繼續(xù),直到達(dá)到范圍的結(jié)束。

在上面的示例中,index是一個(gè)常量,其值在循環(huán)的每次迭代開始時(shí)自動(dòng)設(shè)置。 因此,索引不必在使用之前聲明。 它只是簡單地通過它包含在循環(huán)聲明中,而不需要let聲明關(guān)鍵字。

如果不需要序列中的每個(gè)值,則可以通過使用下劃線代替變量名稱來忽略這些值。

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

上面的示例計(jì)算一個(gè)數(shù)字的值與另一個(gè)數(shù)字的冪(在這種情況下,3為10的冪)。 它使用從1開始并以10結(jié)束的閉合范圍將1的起始值(即3,0的冪)乘以3,十次。對(duì)于該計(jì)算,每次通過循環(huán)的單個(gè)計(jì)數(shù)器值 是不必要的 - 代碼只是執(zhí)行循環(huán)正確的次數(shù)。 用于替換循環(huán)變量的下劃線字符(_)導(dǎo)致單個(gè)值被忽略,并且在循環(huán)的每次迭代期間不提供對(duì)當(dāng)前值的訪問。

使用帶數(shù)組的for-in循環(huán)遍歷其項(xiàng)。

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

詞典中的項(xiàng)目不一定按照插入它們的順序進(jìn)行迭代。 字典的內(nèi)容本質(zhì)上是無序的,并且遍歷它們不保證它們被檢索的順序

while循環(huán)

while循環(huán)執(zhí)行一組語句,直到條件變?yōu)閒alse。 當(dāng)在第一次迭代開始之前不知道迭代次數(shù)時(shí),最好使用這些類型的循環(huán)。 Swift提供了兩種while循環(huán):

  • while在每次通過循環(huán)的開始時(shí)判斷其條件。
  • repeat-while在每次通過循環(huán)結(jié)束時(shí)評(píng)估其條件。

while

while循環(huán)通過評(píng)估單個(gè)條件開始。 如果條件為真,則重復(fù)一組語句,直到條件變?yōu)榧佟?/p>

這里是一個(gè)while循環(huán)的一般形式:

while *condition* {

*statements*

}

游戲板由Int值數(shù)組表示。 它的大小基于一個(gè)稱為finalSquare的常量,用于初始化數(shù)組,并在示例中稍后檢查win條件。 板用26個(gè)零Int值初始化,而不是25(在索引0到25處各一個(gè))。

let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)
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包含一個(gè)梯形圖的底部,它將您移動(dòng)到方形11.為了表示這一點(diǎn),板[03]等于+08,這相當(dāng)于整數(shù)值8(3和11之間的差)。 一元加運(yùn)算符(+ i)與一元減運(yùn)算符(-i)平衡,小于10的數(shù)字用零填充,以便所有電路板定義對(duì)齊。 (風(fēng)格調(diào)整是絕對(duì)必要的,但他們導(dǎo)致更整潔的代碼。)

var square = 0
var diceRoll = 0
while square < finalSquare {
    // roll the dice
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    // move by the rolled amount
    square += diceRoll
    if square < board.count {
        // if we're still on the board, move up or down for a snake or a ladder
        square += board[square]
    }
}
print("Game over!")

然后,當(dāng)前的while循環(huán)執(zhí)行結(jié)束,檢查循環(huán)的條件,看看是否應(yīng)該再次執(zhí)行循環(huán)。 如果玩家已經(jīng)移動(dòng)或超過平方數(shù)25,循環(huán)的條件評(píng)估為假,游戲結(jié)束。

在這種情況下,while循環(huán)是合適的,因?yàn)橛螒虻拈L度在while循環(huán)的開始是不清楚的。 相反,執(zhí)行循環(huán)直到滿足特定條件。

Repeat-While

while循環(huán)的另一個(gè)變體,稱為repeat-while循環(huán),首先執(zhí)行單次通過循環(huán)塊,然后再考慮循環(huán)的條件。 然后它繼續(xù)重復(fù)循環(huán),直到條件為假。

這里是repeat-while循環(huán)的一般形式:

repeat {
    
    statements
    
} while condition
let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)
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



repeat {
    // move up or down for a snake or ladder
    square += board[square]
    // roll the dice
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    // move by the rolled amount
    square += diceRoll
} while square < finalSquare
print("Game over!")

條件語句

Swift提供了兩種向代碼添加條件分支的方法:if語句和switch語句。 通常,您使用if語句來評(píng)估簡單條件,但只有少量可能的結(jié)果。 switch語句更適合于具有多個(gè)可能排列的更復(fù)雜的條件,并且在模式匹配可以幫助選擇要執(zhí)行的適當(dāng)代碼分支的情況下是有用的。

if

在其最簡單的形式中,if語句具有單個(gè)if條件。 它只有在條件為真時(shí)才執(zhí)行一組語句。

var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
    print("It's very cold. Consider wearing a scarf.")
}
// Prints "It's very cold. Consider wearing a scarf."

上面的示例檢查溫度是否小于或等于32華氏度(水的凝固點(diǎn))。 如果是,則打印一條消息。 否則,不會(huì)打印任何消息,并且代碼在if語句的右括號(hào)之后繼續(xù)執(zhí)行。

if語句可以為if條件為假的情況提供另一組語句,稱為else子句。 這些語句由else關(guān)鍵字指示。

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

總是執(zhí)行這兩個(gè)分支之一。 因?yàn)闇囟纫呀?jīng)增加到40華氏度,它不再冷得足以建議戴圍巾,因此觸發(fā)else分支。

您可以將多個(gè)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.")
}
// Prints "It's really warm. Don't forget to wear sunscreen."

Switch

switch語句判斷一個(gè)值,并將其與幾種可能的匹配模式進(jìn)行比較。 然后,它基于成功匹配的第一個(gè)模式,執(zhí)行一個(gè)適當(dāng)?shù)拇a塊。 switch語句提供了用于響應(yīng)多個(gè)潛在狀態(tài)的if語句的替代。

在最簡單的形式中,switch語句將一個(gè)值與一個(gè)或多個(gè)相同類型的值進(jìn)行比較。

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
    
}

每個(gè)switch語句包含多個(gè)可能的情況,每個(gè)都以case關(guān)鍵字開頭。 除了與特定值進(jìn)行比較之外,Swift還為每種情況提供了幾種方法來指定更復(fù)雜的匹配模式。 這些選項(xiàng)將在本章后面介紹。

像if語句的主體,每個(gè)case是一個(gè)單獨(dú)的代碼執(zhí)行分支。 switch語句確定應(yīng)選擇哪個(gè)分支。 此過程稱為打開正在考慮的值。

每個(gè)switch語句必須是窮盡的。 也就是說,所考慮的類型的每個(gè)可能的值必須與開關(guān)情況之一相匹配。 如果不適合為每個(gè)可能的值提供一個(gè)大小寫,則可以定義一個(gè)默認(rèn)大小寫,以覆蓋未明確定位的任何值。 此默認(rèn)情況由default關(guān)鍵字指示,并且必須始終顯示在最后。

此示例使用switch語句來考慮名為someCharacter的單個(gè)小寫字符:

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")
}
// Prints "The last letter of the alphabet"

switch語句的第一種情況與英語字母表的第一個(gè)字母匹配,a,其第二種情況與最后一個(gè)字母z匹配。 因?yàn)榻粨Q機(jī)必須為每個(gè)可能的字符(而不僅僅是每個(gè)字母字符)指定一個(gè)大小寫,所以此switch語句使用默認(rèn)大小寫來匹配除a和z之外的所有字符。 此規(guī)定確保switch語句是詳盡無遺的。

無隱式突破

與C和Objective-C中的switch語句相反,Swift中的switch語句不會(huì)通過每種情況的底部,并且默認(rèn)情況下會(huì)進(jìn)入下一個(gè)語句。 相反,整個(gè)switch語句在第一個(gè)匹配開關(guān)情況完成后立即完成其執(zhí)行,而不需要顯式斷言語句。 這使得switch語句比C中的一個(gè)更安全和更容易使用,并且避免錯(cuò)誤地執(zhí)行多個(gè)開關(guān)情況。

雖然在Swift中不需要break,但是可以使用break語句來匹配和忽略特定的案例,或者在案例完成執(zhí)行之前中斷匹配的案例。 有關(guān)詳細(xì)信息,請(qǐng)參閱切換語句中的中斷。

每個(gè)案例的正文必須包含至少一個(gè)可執(zhí)行語句。 寫入以下代碼是無效的,因?yàn)榈谝环N情況為空:

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // Invalid, the case has an empty body
case "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// This will report a compile-time error.

與C語言中的switch語句不同,此switch語句與“a”和“A”不匹配。 相反,它報(bào)告編譯時(shí)錯(cuò)誤,情況“a”:不包含任何可執(zhí)行語句。 這種方法避免了從一種情況意外跌落到另一種情況,并使得更清楚其意圖的更安全的代碼。

要使用符合“a”和“A”的單個(gè)大小寫進(jìn)行切換,請(qǐng)將這兩個(gè)值組合成一個(gè)復(fù)合大小寫,用逗號(hào)分隔這些值。

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

為了可讀性,復(fù)合case也可以寫在多行。 有關(guān)復(fù)合用例的更多信息,請(qǐng)參閱復(fù)合用例。

間隔匹配

可以檢查開關(guān)情況下的值是否包含在間隔中。 此示例使用數(shù)字間隔為任意大小的數(shù)字提供自然語言計(jì)數(shù):

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).")
// Prints "There are dozens of moons orbiting Saturn."

在上面的例子中,在switch語句中計(jì)算approximCount。 每個(gè)案例將該值與數(shù)字或間隔進(jìn)行比較。 因?yàn)閍pproximCount的值在12到100之間,所以naturalCount被賦值為“dozens”,并且執(zhí)行從switch語句中傳出。

元組

您可以使用元組在同一個(gè)switch語句中測試多個(gè)值。 可以針對(duì)不同的值或值的區(qū)間來測試元組的每個(gè)元素。 或者,使用下劃線字符(_)(也稱為通配符模式)匹配任何可能的值。

下面的示例采用(x,y)點(diǎn),表示為類型(Int,Int)的簡單元組,并將其分類到示例后面的圖表上。

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")
}
// Prints "(1, 1) is inside the box"
屏幕快照 2016-11-19 下午4.53.07.png

switch語句確定點(diǎn)是在原點(diǎn)(0,0),紅色x軸,橙色y軸上,以原點(diǎn)為中心的藍(lán)色4 x 4框內(nèi)還是在框外 。

與C不同,Swift允許多個(gè)開關(guān)情況考慮相同的值或值。 實(shí)際上,點(diǎn)(0,0)可以匹配該示例中的所有四種情況。 但是,如果可能有多個(gè)匹配,則始終使用第一個(gè)匹配大小寫。 點(diǎn)(0,0)將首先匹配case(0,0),因此所有其他匹配的情況將被忽略。

值綁定

開關(guān)案例可以將一個(gè)或多個(gè)匹配的值綁定到臨時(shí)常量或變量,以在案例的主體中使用。 此行為稱為值綁定,因?yàn)橹到壎ǖ桨咐黧w中的臨時(shí)常量或變量。

面的示例采用(x,y)點(diǎn),表示為類型(Int,Int)的元組,并將其分類在以下圖表上:

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))")
}
// Prints "on the x-axis with an x value of 2"
屏幕快照 2016-11-19 下午4.53.07.png

這三個(gè)開關(guān)實(shí)例聲明了占位符常量x和y,它們臨時(shí)從anotherPoint中獲取一個(gè)或兩個(gè)元組值。 第一種情況,case(let x,0)匹配y值為0的任何點(diǎn),并將點(diǎn)的x值賦給臨時(shí)常量x。 類似地,第二種情況,情況(0,let y)匹配x值為0的任何點(diǎn),并將點(diǎn)的y值分配給臨時(shí)常數(shù)y。

where

開關(guān)案例可以使用where子句檢查其他條件。

下面的示例對(duì)以下圖表上的(x,y)點(diǎn)進(jìn)行分類:

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")
}
// Prints "(1, -1) is on the line x == -y"

混合case

共享同一主體的多個(gè)開關(guān)情形可以通過在每個(gè)情形之后寫入幾個(gè)模式來組合,在每個(gè)模式之間使用逗號(hào)。 如果任何模式匹配,則認(rèn)為情況匹配。 如果列表很長,則可以在多行上寫入模式。 例如:

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

switch語句的第一種情況與英語中的所有五個(gè)小寫元音相匹配。 類似地,它的第二種情況匹配所有小寫英語輔音。 最后,默認(rèn)情況下匹配任何其他字符。

復(fù)合用例也可以包括值綁定。 復(fù)合用例的所有模式必須包括相同的值綁定集合,每個(gè)綁定必須從復(fù)合用例中的所有模式獲取相同類型的值。 這確保,無論復(fù)合對(duì)象的哪一部分匹配,代碼在主體中的代碼都可以始終訪問綁定的值,并且該值始終具有相同的類型。

let stillAnotherPoint = (9, 0)
switch stillAnotherPoint {
case (let distance, 0), (0, let distance):
    print("On an axis, \(distance) from the origin")
default:
    print("Not on an axis")
}
// Prints "On an axis, 9 from the origin"

控制傳輸語句

控制轉(zhuǎn)移語句通過將控制從一段代碼轉(zhuǎn)移到另一段代碼來更改代碼執(zhí)行的順序。 Swift有五個(gè)控制轉(zhuǎn)移語句:

  • continue

  • break

  • fallthrough

  • return

  • throw

continue,break和fallthrough語句如下所述。 return語句在函數(shù)中描述,throw語句在使用拋出函數(shù)傳播錯(cuò)誤中描述。

Continue

continue語句告訴循環(huán)停止它正在做什么,并在下一次迭代開始時(shí)再次開始循環(huán)。 它說“我完成了當(dāng)前循環(huán)迭代”,而不完全離開循環(huán)。

以下示例從小寫字符串中刪除所有元音和空格以創(chuàng)建隱藏拼圖短語:

let puzzleInput = "great minds think alike"
var puzzleOutput = ""
let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
for character in puzzleInput.characters {
    if charactersToRemove.contains(character) {
        continue
    } else {
        puzzleOutput.append(character)
    }
}
print(puzzleOutput)
// Prints "grtmndsthnklk"

上面的代碼在每次匹配元音或空格時(shí)調(diào)用continue關(guān)鍵字,導(dǎo)致循環(huán)的當(dāng)前迭代立即結(jié)束,并直接跳轉(zhuǎn)到下一次迭代的開始。

Break

break語句立即結(jié)束整個(gè)控制流語句的執(zhí)行。 當(dāng)您想要比其他情況更早地終止switch或loop語句的執(zhí)行時(shí),break語句可以在switch語句或循環(huán)語句中使用。

中斷循環(huán)語句
當(dāng)在循環(huán)語句中使用時(shí),break立即結(jié)束循環(huán)的執(zhí)行,并將控制轉(zhuǎn)移到循環(huán)閉包括(})后的代碼。 不執(zhí)行來自循環(huán)的當(dāng)前迭代的另外的代碼,并且不開始循環(huán)的進(jìn)一步迭代。中斷在

switch語句中的break
當(dāng)在switch語句中使用break時(shí),break會(huì)使switch語句立即結(jié)束其執(zhí)行,并在switch語句閉括號(hào)(})之后將控制轉(zhuǎn)移到代碼。

以下示例打開字符值,并確定它是否表示四種語言之一的數(shù)字符號(hào)。 為了簡潔,在單個(gè)開關(guān)情況下覆蓋多個(gè)值。

let numberSymbol: Character = "三"  // Chinese symbol for the number 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 {
    print("The integer value of \(numberSymbol) is \(integerValue).")
} else {
    print("An integer value could not be found for \(numberSymbol).")
}
// Prints "The integer value of 三 is 3."

Fallthrough

如果您需要C風(fēng)格的突發(fā)行為,您可以根據(jù)具體情況選擇使用關(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."
}
print(description)
// Prints "The number 5 is a prime number, and also an integer."
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Swift提供了多種控制流聲明。包括while循環(huán)來多次執(zhí)行一個(gè)任務(wù);if,guard和switch聲明來根據(jù)確定...
    BoomLee閱讀 2,002評(píng)論 0 3
  • Swift 提供了類似 C 語言的流程控制結(jié)構(gòu),包括可以多次執(zhí)行任務(wù)的for和while循環(huán),基于特定條件選擇執(zhí)行...
    窮人家的孩紙閱讀 722評(píng)論 1 1
  • 本章將會(huì)介紹 控制流For-In 循環(huán)While 循環(huán)If 條件語句Switch 語句控制轉(zhuǎn)移語句 continu...
    寒橋閱讀 746評(píng)論 0 0
  • [The Swift Programming Language 中文版]本頁包含內(nèi)容: Swift提供了多種流程控...
    風(fēng)林山火閱讀 593評(píng)論 0 0
  • 今天2016年3月6日,拖了好多天,剛好吃完一只百草堂的雞盤腿在床上。最近懶散慣了,有點(diǎn)遲鈍了這幾天也沒讀什么新書...
    福爾摩洋閱讀 259評(píng)論 1 0