新聞中心
編輯推薦:Scala編程語(yǔ)言專題

創(chuàng)新互聯(lián)主營(yíng)蒲縣網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,重慶APP開發(fā)公司,蒲縣h5成都小程序開發(fā)搭建,蒲縣網(wǎng)站營(yíng)銷推廣歡迎蒲縣等地區(qū)企業(yè)咨詢
你可能已經(jīng)使用JAVA若干年了,或許JAVA是你接觸編程來(lái)的***門編程語(yǔ)言,或許是作為比C++更好的一個(gè)選擇。不管怎么樣,你已經(jīng)適應(yīng)了JAVA,并了解她的外觀與內(nèi)在,能夠體會(huì)它的喜怒與哀樂(lè)(原文:You’re comfortable with Java, you know its ins and outs, its moods)。她就像你相處多年的女朋友,或許剛相識(shí)時(shí)那種激情已經(jīng)不再,但你已經(jīng)熟悉怎樣才能讓她開心。簡(jiǎn)單的說(shuō),如果你是一位工匠,則JAVA就是你干活的工具。
然而,你和JAVA的蜜月期過(guò)去了,你在編程語(yǔ)言的選擇上更加務(wù)實(shí)了。只要有足夠的理由,你就可以毫不猶豫去嘗試一種新的語(yǔ)言,但JAVA還沒有足夠的缺陷讓你下定決心離開她。此時(shí),你聽說(shuō)了一個(gè)叫做Ruby的東東,它的簡(jiǎn)潔優(yōu)雅以及巨大的威力給你留下深刻的印象。但你并不是那么確定去使用一個(gè)腳步語(yǔ)言來(lái)構(gòu)建你的企業(yè)應(yīng)用。動(dòng)態(tài)類型以及TextMate確實(shí)都不錯(cuò),但對(duì)于現(xiàn)實(shí)世界,你需要一個(gè)更堅(jiān)實(shí)的支柱。作為一個(gè)實(shí)用主義者,你仍然堅(jiān)持使用JAVA。
這時(shí),好消息傳來(lái)了。一門新的編程語(yǔ)言登上了舞臺(tái)并在開發(fā)者的世界引起了一場(chǎng)風(fēng)暴。Scala貌似具有你對(duì)一門編程語(yǔ)言所期待一切: 靜態(tài)類型,編譯為字節(jié)碼,簡(jiǎn)潔且富有表現(xiàn)力的語(yǔ)法。你可能已經(jīng)被它的一些例子給深深吸引了。它看起來(lái)和JAVA非常相似,但是剔除了JAVA中冗余的語(yǔ)法結(jié)構(gòu)。Scala沒有分號(hào),沒有public static void的方法修飾詞,并且具有靜態(tài)類型推斷機(jī)制。
現(xiàn)在剩下的唯一問(wèn)題就是你應(yīng)該從何開始。你也許嘗試過(guò)去Scala的網(wǎng)站查看相關(guān)知識(shí),但是。。這一切看起來(lái)是那么的函數(shù)化:Lamdas,high-order functions,immutable state,recursion out the wazoo。突然讓人感到前途未卜。
但是,JavaEE的難民們,不必?fù)?dān)心。Scala確實(shí)是一門函數(shù)式的編程語(yǔ)言,但它同樣也是命令式的和面向?qū)ο蟮?。也就是說(shuō),除了書寫那種晦澀難懂的函數(shù)式代碼(原文: It means that you don’t have to write code with the sole purpose of pleasing Haskell Curry),你還有其它的選擇。你可以書寫可讀性很強(qiáng)的代碼,以便你一個(gè)星期之后還能看懂它。將你的代碼給你那些只使用JAVA的同事看,他們甚至也能看懂它。只需要一個(gè)正確的引導(dǎo),你就可以使用Scala來(lái)構(gòu)建你的的JAVA應(yīng)用。
導(dǎo)讀:
如果符合上面所說(shuō)的,那么這個(gè)Scala系列就是為你而準(zhǔn)備的。我已經(jīng)閱讀過(guò)大量有關(guān)Scala的文章以及入門材料(如果你更喜歡函數(shù)式的編程,我強(qiáng)烈推薦你去看Alex Blewitt寫的系列文章),但很少有文章是為了使JAVA開發(fā)比較輕松的轉(zhuǎn)變到Scala來(lái)的。我個(gè)人缺乏FP(函數(shù)式編程)的經(jīng)驗(yàn),因此我肯定不會(huì)在文章中介紹如何將Scheme代碼移植到Scala。該系列文章著重于類比Scala與JAVA,并說(shuō)明為什么Scala比JAVA更好。
起步:
- object HelloWorld extends Application{
- println("Hello, World!")
- }
沒有什么比用代碼來(lái)獲得知識(shí)更直接了,注意到上面的代碼沒有使用分號(hào)。當(dāng)然,如果你愿意還是可以像在JAVA中一樣使用它。但除非你想在同一行中書寫多個(gè)語(yǔ)句,否則分號(hào)不是必須的。這個(gè)代碼示例含義非常清楚,想必你已經(jīng)看明白了它的功能。沒錯(cuò),就是向標(biāo)準(zhǔn)控制臺(tái)輸出一行"Hello, World!"。你可以將這些代碼保存到一個(gè)后綴名為scala的文件中,然后使用scala編譯器編譯它,編譯的結(jié)果是一個(gè)單獨(dú)的class文件(譯者注:這里原文似乎有錯(cuò),我編譯后事實(shí)上生成了兩個(gè)class文件)。你可以像運(yùn)行普通java文件那樣使用java解釋器來(lái)運(yùn)行它,不過(guò)你需要注意一下classpath。最直接的方法是使用scala命令:
- scalac hello.scala
- scala HelloWorld
注意到"hello.scala"文件名沒有?Scala并不像Java一樣強(qiáng)制你在定義public class時(shí),必須保存在文件名與類名相同的文件中。事實(shí)上Scala允許你像C++或Ruby一樣,在同一個(gè)文件中你想定義多少class都可以。但我們***還是遵循Java的命名規(guī)則,因此作為一個(gè)具有良好習(xí)慣的程序員,我們應(yīng)該將上面的代碼保存為"HelloWorld.scala"。
編輯器:
在剛開始接觸Scala,選擇一個(gè)正確的編輯器是個(gè)關(guān)鍵。就像你在使用Java中所了解的那樣,IDE非常有用。但作為一門新生的編程語(yǔ)言,Scala目前還沒有很好的IDE支持,不過(guò)這只是時(shí)間問(wèn)題。在目前,你只有非常有限的選擇:
◆Eclipse(有幾個(gè)不太成熟的Scala插件)
◆Emacs
◆IntelliJ(只支持基本的語(yǔ)法高亮)
◆TextMate
◆VIM
◆jEdit
(譯者注:我使用的是UltraEdit,自己配置一下,能夠自動(dòng)縮進(jìn)與語(yǔ)法高亮以及編譯運(yùn)行,湊合著用了)
上面列的是幾個(gè)主要的選項(xiàng),更完整的列表可以去Scala安裝目錄下的misc/scala-tool-support/文件夾下查看。我個(gè)人推薦使用jEidt或者TextMate;如果你有冒險(xiǎn)精神,可以去嘗試Eclipse上的幾個(gè)插件。Eclipse上的插件具有通常IDE所具有的一些功能(至少Beta版是這樣),譬如語(yǔ)義高亮,代碼自動(dòng)完成,etc。但根據(jù)我的經(jīng)驗(yàn),這些插件都不夠穩(wěn)定以至于難以使用。Scala是一門比Java簡(jiǎn)潔多的語(yǔ)言,它對(duì)IDE的依賴性比Java小得多,因此這些都不是本質(zhì)問(wèn)題,你可以照樣做的很好。
再來(lái)一個(gè)例子
- object HelloWorld2{
- def main(args:Array[String]) = {
- var greeting =""
- for(i <- 0 until args.length){
- greeting += (args(i) + " ")
- }
- if(args.length > 0) greeting =greeting.substring(0, greeting.length -1 )
- println(greeting)
- }
- }
(譯者注: 可能有讀者會(huì)奇怪greeting += (args(i) + " ")這段代碼為什么要用括號(hào),注意,雖然與習(xí)慣不同,但這里的括號(hào)是必須的。因?yàn)樵赟cala里面,運(yùn)算符的優(yōu)先級(jí)由運(yùn)算符***個(gè)字符代表的運(yùn)算符的優(yōu)先級(jí)確定。就是說(shuō)"+="的優(yōu)先級(jí)與"+"的優(yōu)先級(jí)一樣,然后……自己想吧:-)。BTW,Scala里的運(yùn)算符也是方法&對(duì)象。)
將它保存到HelloWorld2.scala,并使用如下命令編譯運(yùn)行:
- scalac HelloWorld2.scala
- scala HelloWorld2 Hello, World!
這次我們使用了不同的方式,通過(guò)命令行向程序傳遞參數(shù),其運(yùn)行的結(jié)果同樣是在控制臺(tái)輸出"Hello, World"。這個(gè)程序比上一個(gè)復(fù)雜一些,首先定義了一個(gè)String類型的變量greeting,然后遍歷一個(gè)數(shù)組,***對(duì)String進(jìn)行適當(dāng)?shù)奶幚?Scala專家肯定會(huì)建議使用Array#deepMkString(String)(類似于Ruby中的Array::join方法),這樣確實(shí)沒錯(cuò)。但我這里主要是為了介紹一些語(yǔ)言上的知識(shí),而不是API的使用)。
首先應(yīng)該注意的是,這里我們定義了一個(gè)main方法。在***個(gè)例子中,我們僅僅繼承了Application類,然后把其它的都交給默認(rèn)構(gòu)造函數(shù)來(lái)做。這樣很好很簡(jiǎn)潔,但有兩個(gè)問(wèn)題:***,我們沒有辦法向程序傳遞命令行參數(shù);第二,對(duì)Scala新手來(lái)說(shuō),這樣看起來(lái)有點(diǎn)魔幻。我將在后面的文章中揭開***個(gè)例子中背后的把戲,現(xiàn)在你記住它就是了。
這個(gè)例子中的main方法是不是已經(jīng)讓你聯(lián)想到了JAVA中的 public static void main?沒錯(cuò),Scala中的main就對(duì)應(yīng)Java中的 public static void main。根據(jù)這個(gè)信息,有經(jīng)驗(yàn)的程序員就可以通過(guò)思考知道更多關(guān)于Scala的知識(shí)。
一開始,你可能有這樣的結(jié)論:Scala中的方法隱含就是public的。這基本正確,Scala中的方法默認(rèn)為public,這意味著Scala中沒有public方法修飾詞(private與protected都有定義)。更進(jìn)一步的,你會(huì)猜測(cè):Scala中的方法默認(rèn)為static的。然而,這次你的猜想不完全正確。
Scala并沒有真正意義上的static屬性。你越早認(rèn)識(shí)到這一點(diǎn),你就越容易理解這門語(yǔ)言。作為替代,Scala有專門的語(yǔ)法讓你實(shí)現(xiàn)與使用sigleton模式(這正是object的含義)。我們實(shí)際上聲明了一個(gè)具有實(shí)例方法main(譯者注:注意,這個(gè)main方法并不是static的)的單實(shí)例類(singleton class)。我將會(huì)在以后詳細(xì)說(shuō)明這一點(diǎn),目前你可以認(rèn)為object就是一個(gè)只具有靜態(tài)方法的類。(譯者注:這個(gè)描述不甚準(zhǔn)確)。
仔細(xì)的觀察這個(gè)例子,我們還可以得到Scala中數(shù)組的語(yǔ)法,以及如何顯式的指明一個(gè)變量的類型。讓我們仔細(xì)研究一下聲明main方法的這行代碼:
- def main(args:Array[String]) = {
這兒,args是一個(gè)Array[String]類型的方法參數(shù)。也就是說(shuō),args是一個(gè)String數(shù)組。在Scala中,Array是一個(gè)具有類型參數(shù)指明其元素類型的類(一個(gè)真正的類,而不是JAVA中那樣)。與之對(duì)等的JAVA語(yǔ)法應(yīng)該類似與下面這樣子(假設(shè)Java中也有一個(gè)Array類):
- public static void main(Array< String> args)
在Scala中,使用variable:Type的語(yǔ)法來(lái)指明變量類型。因此,如果我們想顯式聲明一個(gè)Int類型的變量,應(yīng)該通過(guò)如下方式
- var myInteger:Int
在例子中,我們實(shí)際上聲明了一個(gè)String類型的變量greeting。然而,得益于Scala中的類型推斷機(jī)制,我們并沒有顯式指明變量的類型。下面兩種方式在語(yǔ)義上是等價(jià)的:
- var greeting =""
- var greeting:String =""
在***種方式中,我們顯然知道greeting是一個(gè)String,Scala編譯器也能夠推斷出這一點(diǎn)。這兩個(gè)變量都是靜態(tài)類型檢查的,只不過(guò)***種方式可以少寫7個(gè)字符:-)
細(xì)心的讀者可能還注意到了,例子中的main方法并沒有指明返回類型。這是因?yàn)镾cala同樣可以推斷出來(lái)。如果我們想顯式的指明這點(diǎn),可以像下面這樣:
- def main(args:Array[String]):Unit = {
如前面一樣,類型在方法名之后,并用冒號(hào)隔開。順便提一下,Unit是Scala中的一個(gè)類型,它表示"我不關(guān)心返回的究竟是什么東東"(原文:I-really-don't-care-what-I-return),你可以把它想象為JAVA中void類型與對(duì)象的混合物(譯者注:但Unit不是void,而是一個(gè)實(shí)實(shí)在在的類,也就是說(shuō)Unit類型的方法會(huì)返回一個(gè)Unit對(duì)象)。
數(shù)組的遍歷:
- var greeting =""
- for(i <- 0 until args.length) {
- greeting += (args(i) + " ")
- }
(譯者注: 目前Scala中這種方式遍歷的性能相對(duì)低下,速度大概是JAVA中對(duì)應(yīng)for的1/60。這個(gè)其實(shí)也不會(huì)造成太大的影響,因?yàn)楹臅r(shí)一般不在于for循環(huán)本身,而是循環(huán)體內(nèi)的操作。更何況在Scala中用for的機(jī)會(huì)不多,有更多簡(jiǎn)單實(shí)用的方式去實(shí)現(xiàn)同樣的操作)
這段代碼比剛才那段稍微復(fù)雜點(diǎn)。我們一開始聲明了一個(gè)String類型的變量greeting,然后使用了一個(gè)在Scala中不常用的for循環(huán),這里有一些隱含的類型推斷。有Ruby經(jīng)驗(yàn)的知道在Ruby中的等價(jià)形式:
- for i in 0..(args.size - 1)
- greeting += args[i] + " "
- end
問(wèn)題的關(guān)鍵在于,Scala的for循環(huán)語(yǔ)句需要一個(gè)Range對(duì)象,而這個(gè)Range對(duì)象是由RichInt的until方法建立的。我們可以把上面的代碼分開寫:
- val range =0.until(args.length)
- for(i <- range) {
注意,這里使用"val"而不是"var"聲明變量。使用val,就如java中final的語(yǔ)義,指明range是一個(gè)常量。
在Scala中,我們可以通過(guò)多種不同的形式調(diào)用方法。在這個(gè)例子中,我們看到了"value methodName param"與"value。methodName(param)"這兩種形式的語(yǔ)法是等價(jià)的。另外一個(gè)很重要的事情是,until方法是RichInt具有的,Int并沒有該方法。這里存在一個(gè)隱式類型轉(zhuǎn)換,將Int類型的0轉(zhuǎn)換為scala。runtime。RichInt的一個(gè)實(shí)例。這里不去深究這個(gè)類型轉(zhuǎn)換是怎樣進(jìn)行的,我們關(guān)心的是RichInt類確實(shí)有一個(gè)返回Rangle對(duì)象的until方法。
因此,事實(shí)上這段代碼與JAVA中的下列代碼在邏輯上是等價(jià)的:
- for (int i = 0; i < args.length; i++) {
只不過(guò)在JAVA中是顯式的遍歷整個(gè)區(qū)間,而Scala中使用了一個(gè)Range對(duì)象。
可能你還注意到了,循環(huán)體中訪問(wèn)數(shù)組args元素使用的是圓括號(hào)"()",而不是我們習(xí)慣的方括號(hào)"[]"。
更好的遍歷方式:
在JAVA 5中引入了一個(gè)foreach的語(yǔ)法,像下面這樣:
- for(String arg: args) {
- greeting += arg + " ";
- }
這樣更簡(jiǎn)潔明了。Scala中使用高階函數(shù)(使用函數(shù)做參數(shù)的函數(shù))實(shí)現(xiàn)類似的功能:
- args.foreach {arg =>
- greeting += (arg + " ")
- }
我們可以看到,Array類有一個(gè)foreach方法,這個(gè)方法將一個(gè)函數(shù)作為參數(shù)。foreach方法將會(huì)對(duì)Array里的每一個(gè)元素調(diào)用一次這個(gè)函數(shù),并在調(diào)用的時(shí)候?qū)⑦@個(gè)元素作為函數(shù)參數(shù)傳遞給函數(shù)。這里參數(shù)arg沒有指明類型,但由于我們是對(duì)一個(gè)String數(shù)組遍歷,編譯器能推斷出它的類型是String。我們已經(jīng)提到過(guò),Scala中調(diào)用方法有多鐘不同的方式。這里我們就省略了圓括號(hào)"()",同樣我們也可以寫成:
- args.foreach(arg => {
- greeting += (arg + " ")
- })
Scala中我們可以使用更加簡(jiǎn)潔的書寫方式:
- args.foreach(arg => greeting +=(arg + " "))
不錯(cuò)吧,現(xiàn)在我們將整個(gè)例子重寫成:
- object HelloWorld2 {
- def main(args:Array[String]) = {
- var greeting = ""
- args.foreach(arg => greeting += (arg + " "))
- if (args.length > 0) greeting = greeting.substring(0, greeting.length - 1)
- println(greeting)
- }
- }
Scala的內(nèi)置類型:
因?yàn)镾cala是基于JVM的,因此它從JAVA那兒繼承了大量的API。這意味這你能夠與JAVA交互使用。并且,你所寫的Scala代碼事實(shí)上使用的就是Java API。比如上面的HelloWorld2中我們使用了一個(gè)字符串變量greeting,這個(gè)變量事實(shí)上就是Java中的String類型。再比如,當(dāng)你在Scala中聲明一個(gè)整數(shù)類型(Int),編譯器會(huì)自動(dòng)將它轉(zhuǎn)換為Java的基本類型int。
Scala還內(nèi)置了一些隱式類型轉(zhuǎn)換,當(dāng)需要的時(shí)候編譯器會(huì)自動(dòng)進(jìn)行(就像例子中的Int到RichInt類型的轉(zhuǎn)換)。比如在Scala中將Array[String]類型傳遞給需要String[]類型參數(shù)的函數(shù)時(shí),隱式類型轉(zhuǎn)換就會(huì)發(fā)生。甚至Scala中的類型參數(shù)可以和Java中的泛型相互轉(zhuǎn)化。簡(jiǎn)單的說(shuō),Scala就是一個(gè)披著不同語(yǔ)法外衣的Java。
結(jié)束
Scala不需要復(fù)雜高深的理論或?qū)W術(shù)知識(shí)。一個(gè)普通的開發(fā)者就可以在下一個(gè)企業(yè)WEB應(yīng)用里面使用它。它具有JAVA所缺乏的簡(jiǎn)潔明了的語(yǔ)法,并且保留了JAVA的高效與可靠性。
【相關(guān)閱讀】
- Scala創(chuàng)始人致信:全面解答Scala的泛型優(yōu)勢(shì)
- Scala的類型系統(tǒng):取代復(fù)雜的通配符
- Scala的類型系統(tǒng) 比Java更靈活
- Java程序員,你為什么要關(guān)注Scala
- Scala編程語(yǔ)言
網(wǎng)站欄目:Scala初學(xué)者學(xué)習(xí)資料:main(String[])
鏈接URL:http://www.fisionsoft.com.cn/article/djhddcg.html


咨詢
建站咨詢
