码迷,mamicode.com
首页 > 编程语言 > 详细

8.Swift教程翻译系列——控制流之条件

时间:2017-07-03 13:56:15      阅读:294      评论:0      收藏:0      [点我收藏+]

标签:没有   har   指定   元组   常量   org   integer   div   ural   

3.条件语句

常常会须要依据不同的情况来运行不同的代码。

你可能想要在错误发生的时候运行一段额外的代码,或者当某个值变得太高或者太低的时候给他输出出来。要实现这些需求,你能够使用条件分支。

Swift提供两种方式来实现条件分支。也就是if语句和switch语句。

一般来说If用在可能的情况比較少的简单条件中,当遇到复杂条件有非常多种可能性的时候使用switch会更好。或者要依据模式匹配来推断要运行什么代码的时候switch也非常实用。

if语句

if的最简单形式仅仅有一个单独的if条件。仅仅有当条件为true的时候才会运行if大括号里的代码:

var temperatureInFahrenheit = 30
if 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 = 40
if 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 = 90
if 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 = 72
if 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_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).")
// 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 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 { 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 = 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.”
样例中声明了一个字符串变量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 = 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
这次使用一个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教程翻译系列——控制流之条件

标签:没有   har   指定   元组   常量   org   integer   div   ural   

原文地址:http://www.cnblogs.com/zhchoutai/p/7110473.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!