就是個控制結(jié)構(gòu),Scala能有什么新花樣呢?
導讀
編程語言中最為基礎(chǔ)的一個概念是控制結(jié)構(gòu),幾乎任何代碼都無時無刻不涉及到,其實也就無外乎3種:順序、分支和循環(huán)。本文就來介紹Scala中控制結(jié)構(gòu),主要是分支和循環(huán)。

Scala中的控制結(jié)構(gòu)實質(zhì)上與其他編程語言并無太大差別,需要注意的是Scala中的控制結(jié)構(gòu)大多具有返回值,而其他編程語言中的控制結(jié)構(gòu)一般就僅僅是用于流程控制。本文主要目錄如下:
分支結(jié)構(gòu)
if-else
match-case
循環(huán)結(jié)構(gòu)
for循環(huán)
while循環(huán)
do-while循環(huán)
break和continue
分支結(jié)構(gòu)應(yīng)該編程中最為常用的控制結(jié)構(gòu)了,典型的if-else也是最能代表程序員思維的了。這里首先插一個只有程序員才懂的段子:
女朋友對程序員說:“親愛的,去超市買一個西瓜吧,如果他們還有雞蛋,再買20個”,結(jié)果程員帶了21個西瓜回家。女朋友憤怒地說:“為什么買21個西瓜回來”?程序員答:“因為他們確實有雞蛋”。
這個冷笑話,其實質(zhì)就是一個順序結(jié)構(gòu)+選擇分支結(jié)構(gòu)。那么在Scala中,分支結(jié)構(gòu)當然也是用關(guān)鍵字if-else,更具體的說無外乎以下3種形式:
val num = 2val num: Int = 2// 單分支if(num>1) print("greater")greater// 雙分支if(num>1) print("greater") else print("less")greater// 多分支if(num>2) print("greater") else if(num==2) print("equal") else print("less")equal
if-else是最常規(guī)的分支選擇結(jié)構(gòu),Scala中也不例外。另外,除了以上三種形式外,當然還可以組織嵌套的if-else結(jié)構(gòu),但實質(zhì)都是一樣。形式雖然一樣,但Scala中其實也有其特別之處:那就是Scala中的if-else其實應(yīng)當理解成一個代碼塊,而在Scala中但凡是代碼塊,基本上都對應(yīng)有返回值,所以無論是單分支、雙分支還是多分支,其返回值就是相應(yīng)分支的結(jié)果,雖然這個返回結(jié)果可能為Unit,例如上述print語句后其實就并未產(chǎn)生實際的返回值。同時需指出的是,在單分支中只有if單條語句,當條件不滿足時實際上也是對應(yīng)控制的返回結(jié)果。
正因為if-else都是有返回值的,所以Scala中并未設(shè)立像其他語言中那樣的三元選擇運算符,而是交由if-else完成這一功能。
除了if-else這種經(jīng)典的分支結(jié)構(gòu)外,編程語言中另一經(jīng)典分支結(jié)構(gòu)是switch-case結(jié)構(gòu),這在Scala中也是有所體現(xiàn)的,只不過未提供switch,而是支持功能更為強大的模式匹配:match-case,甚至有人將其稱作是最能體現(xiàn)Scala特色和優(yōu)勢的特性之一。本文作為系列入門文章,僅就其實現(xiàn)最基礎(chǔ)的分支結(jié)構(gòu)做以說明。
scala> num match{ // match 關(guān)鍵字case x if(x<0) => print("<0") // 代入條件判斷case 0 => print("0") // 直接以具體值判斷case 1 => print("1")case _ => print("other") // 用_表示其他情況}other
注:模式匹配在Scala中仍屬于一個代碼塊,也是有返回值的。
在模式匹配中另外值得關(guān)注的一個細節(jié)是,在各匹配分支后,用映射符號"=>"連接條件和執(zhí)行邏輯,這與Scala中函數(shù)的標志性符號是一致的,都表示映射的含義,一定程度上也暗示著模式匹配其實可理解為根據(jù)條件邏輯執(zhí)行一個個的子函數(shù)。
除了選擇分支結(jié)構(gòu),程序中另外一個常用的循環(huán)。實話說,循環(huán)常常是在解決很多算法題目時最先想到的方案,雖然效率不高,但卻非常簡單粗暴和直觀易懂。通常情況下,循環(huán)有3種結(jié)構(gòu):
for
while
do……while
Scala也不例外,而結(jié)合Scala的特性,這三種循環(huán)往往有著更為優(yōu)雅的運用。
1)for循環(huán)。Scala中的for循環(huán)其實與Python中的for循環(huán)比較類似,通常用法是將一個可迭代對象逐一賦值給循環(huán)變量,完成相應(yīng)操作的過程。最基礎(chǔ)的用法如下:
for(i <- 1 to 3) println(i)123
在for循環(huán)內(nèi)部,還可以直接嵌套邏輯判斷條件,術(shù)語說法叫做循環(huán)守衛(wèi),即僅當條件滿足時才進入循環(huán)體執(zhí)行,否則進入下一循環(huán):
for(i <- 1 to 3 if(i%2==1)) print(i)13
除了嵌套邏輯條件判斷,還可以增加一些附屬操作,僅僅是為了便于后續(xù)循環(huán)體執(zhí)行,對循環(huán)執(zhí)行不產(chǎn)生任何影響:
for(i <- 1 to 3; j=2*i) println(j)246
注意在循環(huán)變量與附屬操作之間,需用";"做以分割,表示這是兩句代碼。而在前述的循環(huán)守衛(wèi)中則可加可不加,且一般情況下不加";"更為直觀。
對于嵌套循環(huán),除了類似其他編程語言中的書寫兩重for循環(huán)外,還可直接將兩層循環(huán)變量寫到一個for循環(huán)中,功能一致但邏輯更為清晰:
// 嵌套for循環(huán)常規(guī)寫法scala> for(i <- 1 to 3) for(j <- 1 to i) println(i*j)124369// 精簡寫法scala> for(i <- 1 to 3; j <- 1 to i) println(i*j)124369
for循環(huán)在Scala中仍然屬于一個代碼塊,所以其實也是有返回值的。應(yīng)用這一特性,for循環(huán)其實還有另一個巧妙的運用:由一個迭代器生成另一個迭代器,功能類似于Python中的列表推導式。實現(xiàn)這一功能,需要配合使用關(guān)鍵yield:
scala> val nums = (for(i <- 1 to 5) yield i*2).toListval nums: List[Int] = List(2, 4, 6, 8, 10)
2)while循環(huán)。一般而言,對于具有明確次數(shù)的循環(huán)結(jié)構(gòu)采取for循環(huán)比較合適,而對于循環(huán)次數(shù)未知、需根據(jù)循環(huán)執(zhí)行結(jié)果判斷是否繼續(xù)執(zhí)行的情況則選用while循環(huán)更為合適。Scala中的while循環(huán)與其他編程語言中while用法幾乎完全一致:
scala> var sum = 0var sum: Int = 0scala> var i = 0var i: Int = 0scala> while(sum<10){println(i); sum+=i; i+=1}01234
不過,除了使用場景的不同,Scala中while循環(huán)與for循環(huán)的另一個技術(shù)細節(jié)上的區(qū)別在于:for循環(huán)作為一個代碼塊是有對應(yīng)返回值的(雖然可能返回值可能為空),而while循環(huán)則一定沒有返回值(或者說返回值一定為空)。這一區(qū)別意味著:for循環(huán)既可以用于迭代產(chǎn)生新的迭代結(jié)果,也可以依靠歷次循環(huán)產(chǎn)生相應(yīng)的效果(即執(zhí)行循環(huán)體帶來副作用),而while循環(huán)則只能靠循環(huán)產(chǎn)生的副作用來實現(xiàn)功能。例如,模擬前面使用for循環(huán)+yield產(chǎn)生新的迭代器的過程,強行使用while循環(huán)實現(xiàn)如下:
scala> val arr = new Array[Int](3)val arr: Array[Int] = Array(0, 0, 0)scala> var i = 1var i: Int = 1scala> while(i<=3) {arr(i-1) = i*2; i+=1}scala> arrval res3: Array[Int] = Array(2, 4, 6)
3)do……while循環(huán)。do……while循環(huán)在實際工作中使用還是比較少的,其使用方法與while循環(huán)十分類似,唯一的區(qū)別在于while循環(huán)是先判斷后執(zhí)行;而do……while循環(huán)則是先執(zhí)行再判斷,所以無論如何do……while會至少執(zhí)行一次。
最后值得指出的是,與其他編程語言不同,在Scala中并沒有break和continue兩個關(guān)鍵字,即無法簡單實現(xiàn)循環(huán)中止或者跳過本次循環(huán)這一邏輯。雖然取以代之提供了break()方法,但用起來終究還是不夠方便。那如果就是要實現(xiàn)break和continue兩個需求呢,實際上Scala中可以靈活選用如下3種方式:
增加if條件判斷
for循環(huán)中設(shè)置循環(huán)守衛(wèi)
while循環(huán)中增加相應(yīng)的判斷邏輯
控制結(jié)構(gòu)是編寫任何程序都不得不涉及到的一個概念,對于常用的分支結(jié)構(gòu)、循環(huán)結(jié)構(gòu)在Scala中都有所體現(xiàn),且均具有一定特色,靈活掌握還是比較方便的。

相關(guān)閱讀:
