四、控制流 control flow
1 Switch控制语句
1.1 Switch概述
1.1.1 No Implicit Fallthrough - 没有隐性掉入
相比C和objective-c中的switch语 句,Swift中(如果忘了写break)的switch不会默认的掉落到每个case的下面进入另一 个case。相反,switch语句当第一个遇到的case完成时就完成了它整个的执行,不需要写break。因此比起C语言,swift的switch 更加安全和简单,避免了执行多个case的错误。
每一个switch语句都必须exhaustive(详细),并且每一个所考虑类选可能的值都必须匹配switch中的一个case。如果不能对应到switch中的所有case的值,可以定义个默认的选取器来解决。选取器用default关键字来表示,必须出现在最后。
每个case的主干包括只少一个可执行的语句。下面这样写是无效的,因为第一个case是空的:
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a":
case "A":
println("The letter A")
default:
println("Not the letter A")
}
// this will report a compile-time error
1.1.2 如果有多个匹配对象的,可以用逗号隔开,像下面这样写成多行:
switch some value to consider {
case value 1,
value 2:
statements
}
1.1.3 为特别的switch case选择掉落行为,可以使用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的String型变量并分派一个初始值。然后函数用switch匹配integerToDescribe的 值。如果integerToDescribe的值符合素数列表中的一项,最后的description会增加一段字符,注意数字都是素数。然后用 fallthrough关键字让代码“掉到”default里。default的代码中再额外的给字符串添加些描述,最后switch结束。
如果integerToDescribe不跟素数表中任何一项匹配,那根本就不会匹配switch的第一个case。这里面没有其他的case,因此integerToDescribe直接进入default容器。
NOTE:
fallthrough关键字不检查case里的条件,会直接掉入下一个case。fallthrough简单的让代码执行到下一个case(或default)的代码块中,和标准C语言的特性一样。
1.2 Range Matching - 范围匹配
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."
1.3 Switch语句中Turple的使用
你可以使用元组在相同的switch语句中测试多个值。每一个元组中的元素都可以试着和范围中不同的值进行匹配。另外,用下划线(_)标示符来匹配任意可能的值。
let somePoint = (1, 1) switch somePoint { case (0, 0): println("(0, 0) is at the origin") case (_, 0)://使用下划线(underscore)代表任何可能的值 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轴上,在蓝色4X4的矩形为中心的原点内,或者在矩形外。
与C语言不同,Swift允许多个switch的case考虑相同的值。实际上点(0,0)能匹配例子中所有的四个case。然而,如果多个匹配出现,第一个匹配成功的case将被使用。点(0,0)能首先匹配case(0,0),所以其他所有的case将被忽略。
1.3. Switch中值绑定 Value Bindings
一个switch的case能绑定用于匹配临时常量或变量值,在case的分支代码里使用。这就是value binding(值绑定),因为这些值在case的代码体中是临时常量或变量的“边界”。
下面的例子有一个点(x,y),用元组型(Int,Int)来表示,在图种展示出来如下:
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))") }
三个switch的case都声明了占位常量x和y,暂时从anotherPoint占用一个或两个元组值。
一旦临时常量被声明,他们将在case的代码块中使用。这里他们将作为简写在println函数中打印出来。
注意switch语句没有default的case。最后一个case,case let (x, y),声明了包含两个占位常量可以匹配任何值的元组。作为结果,它匹配任何可能的值,不需要default语句switch就足够完美了。
1.4 Switch中Where的使用
switch的case能使用where子句来进一步判断条件。 下面的例子将点(x,y)在下图种分类:
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"
1.5 给循环(Loop)和Switch添加标签(Lable)
当多个Loop或Switch嵌套时,可以给某个Loop或Switch绑定一个标签,这样可以使用break和continue对特定的Loop和Switch进行操作,
写法:
1.6 switch与循环中的控制语句
continue 结束本次循环
break 终止整个循环
fallthrough 进入下一个case
default 没有任何case匹配时,进入default
2. for in 语句
2.1 使用for-in来遍历集合中的项目,比如数组的范围,排列中的项或者字符串中的字符。
for index in 1...5 { println("\(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
2.2 如果不需要范围的值,可以用下划线替代变量名来忽略这些值:
let base = 3 let power = 10 var answer = 1 for _ in 1...power { answer *= base } println("\(base) to the power of \(power) is \(answer)") // prints "3 to the power of 10 is 59049"
2.3 迭代字典
Dictionary中的项的迭代顺序可能跟它们插入时的顺序不一样。因为Dictionary中的内容本质上是无序的,所以迭代它们不能保证检索时的顺序。
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] for (animalName, legCount) in numberOfLegs { println("\(animalName)s have \(legCount) legs") } // spiders have 8 legs // ants have 6 legs // cats have 4 legs