初探Scala編程:編寫(xiě)腳本,循環(huán)與枚舉
本文接著上一節(jié)內(nèi)容,繼續(xù)介紹一些Scala編程的入門(mén)知識(shí)。
51CTO編輯推薦:Scala編程語(yǔ)言專(zhuān)題
第四步:編寫(xiě)一些Scala腳本
盡管Scala的設(shè)計(jì)目的是幫助程序員建造非常大規(guī)模的系統(tǒng),但它也能很好地縮小到做腳本的規(guī)模。腳本就是一種經(jīng)常會(huì)被執(zhí)行的放在文件中的句子序列。把以下代碼放在hello.scala文件中:
- println("Hello, world, from a script!")
然后運(yùn)行:
- $ scala hello.scala
于是你又會(huì)得到另外的祝詞:
- Hello, world, from a script!
通過(guò)Scala的名為args的數(shù)組可以獲得傳遞給Scala腳本的命令行參數(shù)。Scala里,數(shù)組以零開(kāi)始,通過(guò)在括號(hào)里指定索引訪問(wèn)一個(gè)元素。所以Scala里數(shù)組steps的***個(gè)元素是steps(0),不是像Java里的steps[0]。作為測(cè)試,輸入以下內(nèi)容到新文件helloarg.scala:
// 向***個(gè)參數(shù)打招呼
- println("Hello, " + args(0) + "!")
然后運(yùn)行:
- println("Hello, " + args(0) + "!")
這條命令里,"planet"被作為命令行參數(shù)傳遞,并在腳本里作為args(0)被訪問(wèn)。因此,你會(huì)看到:
- Hello, planet!
注意這個(gè)腳本包括了一條注釋。Scala編譯器將忽略從//開(kāi)始到行尾截止的以及在/*和*/之間的字符。本例還演示了String使用+操作符的連接。這與你的預(yù)期一樣。表達(dá)式"Hello, "+"world!"將產(chǎn)生字符串"Hello, world!"。
第五步:用while循環(huán);用if判斷
要嘗試while,在printargs.scala文件里輸入以下代碼:
- var i = 0
- while (i < args.length) {
- println(args(i))
- i += 1
- }
注意
雖然本節(jié)的例子有助于解釋while循環(huán),但它們并未演示***的Scala風(fēng)格。在下一段中,你會(huì)看到避免用索引枚舉數(shù)組的更好的手段。
這個(gè)腳本開(kāi)始于變量定義,var i = 0。類(lèi)型推斷認(rèn)定i的類(lèi)型是scala.Int,因?yàn)檫@是它的初始值的類(lèi)型,0。下一行里的while結(jié)構(gòu)使得代碼塊(大括號(hào)之間的代碼)重復(fù)執(zhí)行直到布爾表達(dá)式i < args.length為假。args.length給出了args數(shù)組的長(zhǎng)度。代碼塊包含兩句話(huà),每個(gè)都縮進(jìn)兩個(gè)空格,這是Scala的推薦縮進(jìn)風(fēng)格。***句話(huà),println(args(i)),輸出第i個(gè)命令行參數(shù)。第二句話(huà),i += 1,讓i自增一。注意Java的++i和i++在Scala里不起作用,要在Scala里自增,必須寫(xiě)成要么i = i + 1,或者i += 1。用下列命令運(yùn)行這個(gè)腳本:
- $ scala printargs.scala Scala is fun
你將看到:
- Scala
- is
- fun
想要更好玩兒一些,就把下列代碼輸入到新文件echoargs.scala:
- var i = 0
- while (i < args.length) {
- if (i != 0)
- print(" ")
- print(args(i))
- i += 1
- }
- println()
在這個(gè)版本里,用print調(diào)用替代了println調(diào)用,這樣所有參數(shù)將被輸出在同一行里。為了更好的可閱讀性,你應(yīng)該用if(i != 0)檢查,除了***個(gè)之外的每個(gè)參數(shù)前插入一個(gè)空格。由于***次做while循環(huán)時(shí)i != 0會(huì)失敗,因此在頭一個(gè)參數(shù)之前不會(huì)輸出空格。***,你應(yīng)該在末尾多加一個(gè)println,這樣在輸出所有參數(shù)之后會(huì)有一個(gè)換行。這樣你的輸出就非常漂亮了。如果用下面的命令運(yùn)行腳本:
- $ scala echoargs.scala Scala is even more fun
就能得到:
- Scala is even more fun
注意Scala和Java一樣,必須把while或if的布爾表達(dá)式放在括號(hào)里。(換句話(huà)說(shuō),就是不能像在Ruby里面那樣在Scala里這么寫(xiě):if i < 10。在Scala里必須寫(xiě)成if (i < 10)。)另外一點(diǎn)與Java類(lèi)似的,是如果代碼塊僅有一個(gè)句子,大括號(hào)就是可選的,就像echoargs.scala里面if句子演示的。并且盡管你沒(méi)有看到,Scala也和Java一樣使用分號(hào)分隔句子的,只是Scala里的分號(hào)經(jīng)常是可選的,從而可以釋放你的右小手指。如果你有點(diǎn)兒羅嗦的脾氣,那么就把echoargs.scala腳本寫(xiě)成下面的樣子好了:
- var i = 0;
- while (i < args.length) {
- if (i != 0) {
- print(" ");
- }
- print(args(i));
- i += 1;
- }
- println();
第六步:用foreach和for枚舉
盡管或許你沒(méi)意識(shí)到,在前一步里寫(xiě)while循環(huán)的時(shí)候,你正在用指令式:imperative風(fēng)格編程。指令式風(fēng)格,是你常常使用像Java,C++和C這些語(yǔ)言里用的風(fēng)格,一次性發(fā)出一個(gè)指令式的命令,用循環(huán)去枚舉,并經(jīng)常改變共享在不同函數(shù)之間的狀態(tài)。Scala允許你指令式地編程,但隨著你對(duì)Scala的深入了解,你可能常會(huì)發(fā)現(xiàn)你自己在用一種更函數(shù)式:functional的風(fēng)格編程。實(shí)際上,本書(shū)的一個(gè)主要目的就是幫助你變得對(duì)函數(shù)式風(fēng)格感覺(jué)像和指令式風(fēng)格一樣舒適。
函數(shù)式語(yǔ)言的一個(gè)主要特征是,函數(shù)是***類(lèi)結(jié)構(gòu),這在Scala里千真萬(wàn)確。舉例來(lái)說(shuō),另一種(簡(jiǎn)潔得多)打印每一個(gè)命令行參數(shù)的方法是:
- args.foreach(arg => println(arg))
這行代碼中,你在args上調(diào)用foreach方法,并把它傳入函數(shù)。此例中,你傳入了帶有一個(gè)叫做arg參數(shù)的函數(shù)文本:function literal。函數(shù)體是println(arg)。如果你把上述代碼輸入到新文件pa.scala,并使用命令執(zhí)行:
- $ scala pa.scala Concise is nice
你會(huì)看到:
- Concise
- is
- nice
前例中,Scala解釋器推斷arg的類(lèi)型是String,因?yàn)镾tring是你調(diào)用foreach的那個(gè)數(shù)組的元素類(lèi)型。如果你喜歡更顯式的,你可以加上類(lèi)型名,不過(guò)如此的話(huà)你要把參數(shù)部分包裹在括號(hào)里(總之這是語(yǔ)法的普通形式):
- args.foreach((arg: String) => println(arg))
運(yùn)行這個(gè)腳本的結(jié)果與前一個(gè)相同。
如果你更喜歡簡(jiǎn)潔的而不是顯式的風(fēng)格,就可以充分體會(huì)到Scala特別簡(jiǎn)潔的優(yōu)越性。如果函數(shù)文本由帶一個(gè)參數(shù)的一句話(huà)組成,你都不需要顯式命名和指定參數(shù)。 這樣,下面的代碼同樣有效:
- args.foreach(println)
總而言之,函數(shù)文本的語(yǔ)法就是,括號(hào)里的命名參數(shù)列表,右箭頭,然后是函數(shù)體。語(yǔ)法演示在圖2.2中。
現(xiàn)在,到這里你或許想知道那些你在指令式語(yǔ)言如Java或C里那么信任的for循環(huán)到哪里去了呢。為了努力引導(dǎo)你向函數(shù)式的方向,Scala里只有一個(gè)指令式for(稱(chēng)為for表達(dá)式:expression)的函數(shù)式近似。目前你還看不到他們?nèi)康牧α亢捅磉_(dá)方式,直到你讀到了(或者先瞄一眼)第7.3節(jié),我們僅僅帶您在這里領(lǐng)略一下。創(chuàng)建一個(gè)新文件forargs.scala,輸入以下代碼:
- for (arg <- args)
- println(arg)
這個(gè)表達(dá)式里“for”之后的括號(hào)包含arg<-args。 <-右側(cè)的是熟悉的args數(shù)組。<-左側(cè)的是“arg”,val的名稱(chēng)(不是var)。(因?yàn)榭倸w是val,你只要寫(xiě)arg就可,不要寫(xiě)成val arg。)盡管arg可能感覺(jué)像var,因?yàn)樗诿看蚊杜e都會(huì)得到新的值,但它的確是val : arg不能在for表達(dá)式的函數(shù)體中重新賦值。取而代之,對(duì)每個(gè)args數(shù)組的元素,一個(gè)新的arg val將被創(chuàng)建并初始化為元素值,然后for的函數(shù)體將被執(zhí)行。
如果執(zhí)行forargs.scala腳本:
- $ scala forargs.scala for arg in args
可以看到:
- for
- arg
- in
- args
Scala的for表達(dá)式可以比這個(gè)做得更多,但是這個(gè)例子足以讓你起步了。
本文節(jié)選自《Programming in Scala》
【相關(guān)閱讀】