8.Swift教程翻譯系列——控制流程之條件

來源:互聯網
上載者:User

標籤:沒有   har   指定   元組   常量   org   integer   div   ural   

3.條件陳述式

常常會須要依據不同的情況來運行不同的代碼。

你可能想要在錯誤發生的時候運行一段額外的代碼,或者當某個值變得太高或者太低的時候給他輸出出來。要實現這些需求,你能夠使用條件分支。

Swift提供兩種方式來實現條件分支。也就是if語句和switch語句。

一般來說If用在可能的情況比較少的簡單條件中,當遇到複雜條件有非常多種可能性的時候使用switch會更好。或者要依據模式比對來推斷要運行什麼代碼的時候switch也非常實用。

if語句

if的最簡單形式僅僅有一個單獨的if條件。僅僅有當條件為true的時候才會運行if大括弧裡的代碼:

var temperatureInFahrenheit = 30if temperatureInFahrenheit <= 32 {<span style="white-space:pre"></span>println("It's very cold. Consider wearing a scarf.")}// prints "It's very cold. Consider wearing a scarf."
上面的範例檢查溫度是不是小於等於32度(水結冰的問題呢,不是攝氏度吧)。假設是,輸出語句就會運行,假設不是就不會運行,接著運行If大括弧後面的語句。

if語句還能夠提供另外一個可選擇的語句塊。就是else分支,當if條件計算為false的時候將運行else的代碼。以下是包括else的代碼:

temperatureInFahrenheit = 40if temperatureInFahrenheit <= 32 {<span style="white-space:pre"></span>println("It's very cold. Consider wearing a scarf.")} else {<span style="white-space:pre"></span>println("It's not that cold. Wear a t-shirt.")}// prints "It's not that cold. Wear a t-shirt."

兩個分支總有一種會運行。由於溫度上升到40度了。已經比32度要高了。所以啟動並執行是else分支。

你還能夠將多個if連結起來,使用很多其它的分支:

temperatureInFahrenheit = 90if temperatureInFahrenheit <= 32 {<span style="white-space:pre"></span>println("It's very cold. Consider wearing a scarf.")} else if temperatureInFahrenheit >= 86 {<span style="white-space:pre"></span>println("It's really warm. Don't forget to wear sunscreen.")} else {<span style="white-space:pre"></span>println("It's not that cold. Wear a t-shirt.")}// prints "It's really warm. Don't forget to wear sunscreen."
這裡加入了一個if語句來響應特別熱的溫度。最後一個else還在。用來作為既不太熱也不太冷的溫度的響應。

只是最後一個else是可選的,假設說各種情況不用所有都處理:

temperatureInFahrenheit = 72if temperatureInFahrenheit <= 32 {<span style="white-space:pre"></span>println("It's very cold. Consider wearing a scarf.")} else if temperatureInFahrenheit >= 86 {<span style="white-space:pre"></span>println("It's really warm. Don't forget to wear sunscreen.")}
這個範例中,溫度既不會太冷而運行if。也不會太熱而運行else if。所以什麼都沒有輸出。

switch語句

switch語句是將某個值與若干個可能的情況進行匹配。

然後運行第一個匹配上的情況相應的代碼。

switch語句為多種可能情況的if語句提供了還有一種選擇。

switch的最簡單形式是某個簡單類型的值跟幾個同類型的值進行比較看是否相等:

switch some value to consider {<span style="white-space:pre"></span>case value 1 :<span style="white-space:pre"></span>respond to value 1<span style="white-space:pre"></span>case value 2 ,value 3 :<span style="white-space:pre"></span>respond to value 2 or 3<span style="white-space:pre"></span>default:<span style="white-space:pre"></span>otherwise, do something else}
switch語句由多個可能匹配的case組成。

除了比較特殊的值。swift還提供幾種方式來給每種情況指定更複雜的匹配模式。這些內容在本章後面會介紹的。

switch的各個case都是獨立的運行分支,switch語句決定哪條分支被運行。

switch語句必須是完好的,也就是說全部要考慮的情況都必須跟一個case匹配。

最好是給每一種可能的情況都提供一個case,你還能夠定義一個預設的情況,假設前面全部情況都沒匹配上就會運行這個預設的分支,預設分支使用defaultkeyword,並且必須出來再全部的case之後。

以下範例使用switch語句來檢查一個單獨的小寫字母someCharacter:

let someCharacter: Character = "e"switch someCharacter {<span style="white-space:pre"></span>case "a", "e", "i", "o", "u":<span style="white-space:pre"></span>println("\(someCharacter) is a vowel")<span style="white-space:pre"></span>case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":<span style="white-space:pre"></span>println("\(someCharacter) is a consonant")<span style="white-space:pre"></span>default:<span style="white-space:pre"></span>println("\(someCharacter) is not a vowel or a consonant")}// prints "e is a vowel"
上面switch的第一個case匹配隨意的母音字母。第二個case匹配隨意的輔音字母。要寫出其它所有的字母有點兒不太可能,所以最後使用了default來匹配除了母音和輔音字母以外的隨意字元。加上這個default就保證了switch語句的完備性。

沒有隱式順序運行

與C或者OC裡的switch對照,swift的switch語句預設不會再去一個個匹配已經匹配到的case後面的case,當程式匹配到一個case,運行case的代碼塊,switch就結束了。代碼塊末尾不須要使用break語句。

這使得switch語句比C更安全簡單,避免了由於忘記寫break造成程式運行了好幾個case。

NOTE 假設你認為沒有break看著彆扭,你也能夠加上。

每一個case都必須包括至少一條語句。以下這樣寫就是錯的,由於第一個case是空的:

let anotherCharacter: Character = "a"switch anotherCharacter {<span style="white-space:pre"></span>case "a":<span style="white-space:pre"></span>case "A":<span style="white-space:pre"></span>println("The letter A")<span style="white-space:pre"></span>default:<span style="white-space:pre"></span>println("Not the letter A")}// this will report a compile-time error
這可跟C語言不一樣了,switch語句不會同一時候匹配"a"和“A”,而是給case "a":報編譯錯誤“does not contain any executeable statements(不包括不論什麼可啟動並執行語句)”。這樣避免了不小心從一個case再運行到還有一個case。使代碼又安全又意圖清晰。

假設要一個case匹配多種情況,就使用逗號分隔。並且非常長的能夠分行寫:

switch some value to consider {<span style="white-space:pre"></span>case value 1 ,<span style="white-space:pre"></span>   value 2 :<span style="white-space:pre"></span>statements}
NOTE 假設要讓匹配命中後面的case順序運行,能夠使用fallthroughkeyword。後面也會專門介紹。

範圍匹配

switch的case匹配的值也能夠使用範圍。

以下的範例使用數字範圍來顯示數位自然語言形式

let count = 3_000_000_000_000let countedThings = "stars in the Milky Way"var naturalCount: Stringswitch 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).")// prints "There are millions and millions of stars in the Milky Way.”
元組

你能夠在switch語句中使用元組來對多個值做推斷。元組中的元素各自都能被單個值或者某個範圍來比較。或者你也能夠使用底線來讓他匹配隨意值。

以下舉例使用(Int, Int)類型的元組(x,y)來表示一個點,然後給點分類:

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")}// prints "(1, 1) is inside the box”

switch語句推斷點是不是在原點(0,0)。或者紅色的x軸上,或者橘黃色的y軸上,或者是在藍色地區內,或者是來藍色地區以外。

和C不一樣的是,Swift能夠多個case使用反覆的值,其實(0,0)是能夠匹配上面四個case的。

可是就算多個case都能匹配,第一個被匹配的才會被運行。

所以點(0,0)會匹配第一個(0,0)的情況,其它的就被忽略了。

值綁定

case能夠將他匹配的值綁定到暫時常量或者變數中,然後在case的代碼塊裡使用。

這就是值綁定,由於值僅僅是在case代碼塊裡被綁定給某個暫時常量或者變數。

以下的範例跟上面幾乎相同

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))")}// prints "on the x-axis with an x value of 2”

switch語句推斷點是否在x軸上,或者在y軸上,或者其它地方。

三個case生命了常量x和y,用來從元組anotherPoint中暫時擷取x或者y或者x和y的值。第一個case,caes (let x,0)匹配不論什麼y座標為0的點。而且把這個點得x座標賦值給暫時常量x,第二個case, case (0, let y)匹配全部x座標為0的點,然後將這個點得y座標賦值給暫時常量y。

僅僅要是暫時常量被生命了。那在這個case的代碼塊裡就能夠使用這個常量。

對於這個範例來說,他們被用來輸出座標的值。

注意這個switch是沒有default的,由於最後一個case let(x, y)使用了兩個預留位置,那他就會匹配全部的點。所以也就不用再加default了,這個switch已經非常完整了。

上面的範例中。x和y被定義成常量,那是由於我們在case裡面沒有必要去改動座標的值。假設你想聲明成變數就用varkeyword,假設是這種話,暫時變數應該是已經被建立而且用合適的值初始化了得。

不論什麼對於該變數的改動都僅僅能在這個case裡面有效。

where

case還能夠使用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")}// prints "(1, -1) is on the line x == -y”

switch推斷點是否在綠色直線(x=y)上,或者在紫色直線(x = -y)上。或者其它地方。

三個case都聲明了常量x和y,臨時儲存了點得座標值。

這些常量也被用來作為case中where語句的一部分。來建立一個動態過濾器。這個case僅僅有噹噹前匹配的點滿足where的運算式計算結果為true的時候才會被匹配。

和前一個範例一樣,最後一個case會匹配剩下全部的點,所以這個switch也沒有加default。


4.控制轉移語句

控制轉移語句能夠將控制從一段代碼轉移到還有一段代碼,以此來改變代碼的運行順序。Swift有四種控制轉移語句

continue

break

fallthrough

return

以下介紹前三種。最後一個return會在函數的章節裡再介紹。

continue

continue語句告訴迴圈停止當前的迴圈,然後開始下一次迴圈。

也就是說“本次迴圈任務已經運行完了”,而不會全然跳出迴圈。

NOTE 在for-condition-increment型的迴圈中。假設使用了continue語句,遞增語句還是會被啟動並執行。迴圈本身的順序還是正常的,僅僅是迴圈體被跳過了而已。

以下的範例將小寫字串中的母音字母和空格都去掉了,最後產生一個沒什麼含義的短語

let puzzleInput = "great minds think alike"var puzzleOutput = ""for character in puzzleInput {    switch character {    case "a", "e", "i", "o", "u", " ":        continue    default:        puzzleOutput += character    }}println(puzzleOutput)// prints "grtmndsthnklk”
上面的代碼僅僅要碰到母音或者空格就使用continue。當前的迴圈就被終止,開始下一次迴圈了。

這樣能夠讓switch僅僅匹配並忽略母音字母及空格,而不是要求代碼塊匹配全部須要輸出的字元。

break

break語句終止當前的整個控制流程。break能夠用來switch或者迴圈其中來提前退出整個switch或者迴圈。

在迴圈中break

假設在迴圈語句中使用break,整個迴圈立刻就被終止了,轉移運行迴圈的大括弧後面的代碼。

當前迴圈不會被運行了,下一次以及以後的迴圈也不會被運行了。

在switch中break

假設在switch中使用break。整個switch也馬上被終止,開始運行switch以後的代碼了。能夠使用break來匹配而且忽略一種或多種情況。由於swift的switch是完備的,而且不同意空分支。有時為了有益匹配而且忽略某些情況,來使意圖更明顯。那麼就把break作為想要忽略的case代碼塊的唯一一句代碼。當那個case被匹配到了,整個switch語句立刻就被終止了。

NOTE 假設case僅僅有凝視。編譯器會報編譯錯誤。

凝視不是語句。也不會是case被忽略。假設想讓case被忽略掉就用break。

以下的範例通過switch來推斷字元是否代表以下四種語言之中的一個。

為了簡潔這邊在一個case中匹配多個值:

let numberSymbol: Character = "三"  // Simplified Chinese for the number 3var possibleIntegerValue: Int?

switch numberSymbol {case "1", "?", "一", "?": possibleIntegerValue = 1case "2", "?", "二", "?": possibleIntegerValue = 2case "3", "?", "三", "?": possibleIntegerValue = 3case "4", "?", "四", "?": possibleIntegerValue = 4default: break}if let integerValue = possibleIntegerValue { println("The integer value of \(numberSymbol) is \(integerValue).")} else { println("An integer value could not be found for \(numberSymbol).")}// prints "The integer value of 三 is 3.”

上面的範例檢查numberSymbol來決定是否為拉丁文,阿拉伯數字。中文或者泰文的1,2,3,4。假設發現某個匹配的,那個case就給可選變數possibleIntegerValue賦值。

當switch運行完的時候,使用可選值綁定來推斷possibleIntegerValue是否有值。由於這個可選變數隱式使用nil初始化的。所以假設僅僅有當某個case給他賦值的時候以下的if才會通過。

要列出上面範例中全部可能的字元就不太實際了,所以用了個deault來匹配剩下的全部字元。這個分支不須要做不論什麼操作。所以就僅僅寫了一個break語句。僅僅要最後的default被匹配,整個switch就被break終止了。開始運行以下的if了。

fallthrough

swift的switch語句假設匹配到了某個case是不會再繼續向下啟動並執行,運行完這個case的代碼整個switch也就結束了。可是在C裡面是要求在case的結尾加一個break才幹有這種效果。避免了預設掛穿運行意味著swift的switch語句比C要更加簡潔而且可預料,也避免了由於忘記寫break而多運行了其它的case。

假設你確實須要像C那樣貫穿的特性。你能夠通過使用fallthroughkeyword來滿足。以下的自理使用fallthrough來建立數位文本描寫敘述:

let integerToDescribe = 5var description = "The number \(integerToDescribe) is"switch integerToDescribe {case 2, 3, 5, 7, 11, 13, 17, 19:    description += " a prime number, and also"    fallthroughdefault:    description += " an integer."}println(description)// prints "The number 5 is a prime number, and also an integer.”
範例中聲明了一個字串變數description而且給他賦初始值。

然後使用switch來測試integerToDescribe的值。假設是第一個case中的某個素數。就在description後面加一段文字說明這個數字是素數。然後使用fallthroughkeyword來讓程式繼續直接進入下一個case default,default case給description加入了其它的描寫敘述資訊,然後整個switch才結束。

假設integerToDescribe沒有在第一個case其中。第一個case也就不會被匹配。也沒有其它特殊的分支了,所以就被default匹配了。

當switch語句運行完以後,數位描寫敘述被使用println函數輸出。

這個範例中數字5被正確的認出是素數。

NOTE fallthrough不會檢查下一個將要匹配的分支的條件,他僅僅是簡單地讓程式直接進入下一個分支,就像C標準的switch語句一樣。
標籤語句

你能夠通過在switch或者迴圈其中嵌套其它的switch或者迴圈來實現複雜的控制流程結構。

switch和迴圈都能夠使用break語句來提前結束程式。可是有時候須要指定你想跳出的是哪個迴圈或者switch。比方說你嵌套了好幾個迴圈。指明break應該跳出哪個迴圈就非常須要了。

要想達到這個目的,你能夠給迴圈或者switch設定一個標籤,然後再break或者continue後面加上這個標籤。就能讓break或者continue影響這個迴圈或者switch了。

標籤語句是通過在語句本身前面加上標籤名稱再加上冒號。以下有個給while語句使用標籤的範例。這個規則對於全部的迴圈和switch都是通用的:

label name: while condition {    statements}
以下的範例使用帶標籤的break和continue語句又一次實現上面寫過的蛇與梯子的遊戲。

這次遊戲規則要加一條:若且唯若你身在第25格的時候才算過關

假設某次擲色子然後跳到25格以外了,那就又一次擲色子。一直到你站在25格上。遊戲棋盤跟前面的一樣:

finalSquare,borad,square以及diceRoll的初始化方式跟前面也是一樣的:

let finalSquare = 25var board = Int[](count: finalSquare + 1, repeatedValue: 0)board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08var square = 0var diceRoll = 0
這次使用一個while迴圈和一個switch來實現遊戲邏輯。while迴圈有個標籤gameLoop,表明這是遊戲的主迴圈。

while迴圈的迴圈條件是 while square != finalSquare。也就是說你必須站在第25格上才幹過關:

gameLoop: while square != finalSquare {    if ++diceRoll == 7 { diceRoll = 1 }    switch square + diceRoll {    case finalSquare:        // diceRoll will move us to the final square, so the game is over        break gameLoop    case let newSquare where newSquare > finalSquare:        // diceRoll will move us beyond the final square, so roll again        continue gameLoop    default:        // this is a valid move, so find out its effect        square += diceRoll        square += board[square]    }}println("Game over!")
每次迴圈先擲色子。可是這次不是依據色子直接移動了。而是用switch來依據移動的結果來推斷是否同意移動:

假設這個色子能把你移動到最後一格上,遊戲就結束了,break gameLoop語句就把程式轉移到while迴圈以後了,然後遊戲也就結束了。

假設這個色子把你移動到棋盤外面了,那這個移動是非法的,你要又一次擲色子。continue gameLoop語句結束了當前進行中的迴圈,而且開始下次迴圈。
其它情況。移動是合法的且不會讓你過關的。

你就依照色子的數字移動,然後檢查當前位置是不是蛇頭或者梯子能夠移動的。

然後當前迴圈結束,返回到while條件陳述式推斷是否須要進行下一次迴圈。

NOTE 假設上面的break語句不適用gameLoop標籤。那break僅僅會跳出switch而不會終止整個while迴圈。使用gameLoop標籤能夠清楚的指明須要結束哪個語句。

還要注意的時當在gameLoop迴圈裡要使用continue進行下一次迴圈的時候能夠不用gameLoop標籤的。由於這個遊戲裡僅僅有一個迴圈,所以沒有必要指明continue對誰起作用。


可是你要用也無妨。

這樣能夠使程式邏輯清晰易於理解。

8.Swift教程翻譯系列——控制流程之條件

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.