一个 C++ 程序员眼中的 Swift(三)
On 2014-12-03 23:22:15 By Soli一个 C++ 程序员眼中的 Swift(三)
接下来的内容就更有趣了,方便的for-in
、强大的switch
、 穿越的break
等等。每一个都戳到了 C++ 程序员的痛处或痒处。
for-in
现在大多数语言都已支持
for-in
语句了。C/C++ 还在固守成规。Swift 的
for-in
语句与它的区间运算符简直是绝配,写个循环如此简单:var sum = 0 for i in 0..<10 { sum += i }
迭代数组也极其方便:
let names = ["xiaoming", "xiaolan", "xiaohong"] for i in 0..<names.count { println("\(names[i])") }
迭代数组何必需要下标?
let names = ["xiaoming", "xiaolan", "xiaohong"] for name in names { println("\(name") }
往下看前先默念一遍 C++ 中如何迭代
std::map
的。然后再看 Swift 是怎么做的:let scores = ["xiaoming":98, "xiaolan":89, "xiaohong":99] for (name, score) in scores { println("\(names) got \(score)") }
增强的
switch
不再有漏写
break
的烦恼。Swift 的switch
中每个case
都是默认break
的,无需在最后写break
。但在 C/C++ 中,有时我们是故意不写
break
的。Swift 为了支持这一特性,增加了fallthrough
语句。虽然增加了新的语句,但这更符合实际情况。在大多数情况下我们想要的是
break
,而极少数情况下才需要fallthrough
。而默认值应该是照顾大多数情况的。所以,Swift 中是默认break
而需要显式写fallthrougn
,而 C/C++ 中却是默认fallthrough
而需要显式写break
。下面是个例子:
let skills = 2 var description = "You are a " switch skills { case 2: description += "senior " fallthrough case 1: description += "expert" default: description += "good guy" } println(description)
Swift 要求
switch
中的case
必须是完备的,即列举所有的情况。当然,可以使用default
来覆盖那些我们不关心的情况。Swift 还要求每个
case
下必须含有有效的语句(注释不算)。所以,如果你想忽略某个(些)case
,你需要显式的写个break
。每个
case
可以写多个条件:switch result { case "true", "True": println("correct") case "false", "False": println("wrong") default: println("invalid") }
case
里的条件不只是一个或多个的值,还可以是区间:switch temperature { case -40 ... -10: println("frigid") case -10 ... 5: println("cold") case 5 ... 20: println("cool") case 20 ... 28: println("warm") case 28 ... 40: println("hot") default: println("not for human beings") }
还可以是元组:
switch (strength, magic) { case (0, 0): println("die") case (0, _): // 下划线表示该项可为任意值。 println("revive") case (80...100, 80...100) println("attack") case (0...30, _): println("escape") default: println("defense") }
可以看到,各个条件是可以重叠甚至相同的。Swift 只执行第一个匹配到的条件下的语句。
值绑定
有时你需要在
case
里的代码段里使用case
所匹配到的值。这时可能就会用到值绑定。比如:let point = (0, 3) switch point { case (let row, 0): println("rown number of \(row)") case (0, let col): println("headline of \(col)") case let (row, col): println("data of (\(row), \(col))") }
当然,也可以用
var
声明变量来进行值绑定。这个特性除了方便之外,似乎没有什么用。因为我们可以通过
point
这个常量来引用我们需要的值。比如:let point = (0, 3) switch point { case (_, 0): println("rown number of \(point.0)") case (0, _): println("headline of \(point.1)") default: println("data of (\(point.0), \(point.1))") }
用
where
给case
加上条件判断。这让switch
更像一系列if...else
了。let point = (3,3) switch point { case (_, _) where point.0 > 0 && point.1 > 0: println("point is on the first quadrant") case let (x, y) where x > 0 && y < 0: // 用了值绑定,是不是方便多了。 println("point is on the forth quadrant") case let (x, y) where x < 0 && y > 0: println("point is on the second quadrant") case let (x, y) where x < 0 && y < 0: println("point is on the third quadrant") default: println("point is on the axes") }
带标签的语句
在嵌套循环中,有时我们想直接跳出到最外层循环。另外,在嵌套的
switch
里,或循环和switch
混合嵌套的情况下,同样有这种需求。在 C/C++ 中可以使用
goto
语句来实现。有时这也不失为一种优雅的办法。在很多教材或文章中,甚至在很多老师和前辈的口中,goto
语句都被妖魔化了。为了避免使用goto
,宁可增加很多标志变量再绕几个弯儿来实现一句goto
就可以实现的逻辑。即使有充分的理由在代码中使用了goto
,心理上也承受着会被别人嘲讽的压力。在 Swift 中,你完全可以抛掉这些心理负担了。因为只需在
for
、while
或switch
等语句前加个标签,你就可以随心所欲的break
或continue
指定的控制流了。fl: for i in 0...20 { sl: switch i { case 0: fallthrough case 1: break sl default: for j in 2..<i { switch i % j { case 0: continue fl default: break } } println("\(i)") } }
未完待续