Scala是一門多範式的程式設計語言,一種類似java的程式設計語言 [1] ,設計初衷是實作可伸縮的語言 [2] 、并內建面向對象程式設計和函數式程式設計的各種特性。
Scala程式設計語言抓住了很多開發者的眼球。如果你粗略浏覽Scala的網站,你會覺得Scala是一種純粹的面向對象程式設計語言,而又無縫地結合了指令式程式設計和函數式程式設計風格。Christopher Diggins認為:
不太久之前程式設計語言還可以毫無疑意地歸類成“指令式”或者“函數式”或者“面向對象”。Scala代表了一個新的語言品種,它抹平了這些人為劃分的界限。
根據David Rupp在部落格中的說法,Scala可能是下一代Java。這麼高的評價讓人不禁想看看它到底是什麼東西。
Scala有幾項關鍵特性表明了它的面向對象的本質。例如,Scala中的每個值都是一個對象,包括基本資料類型(即布爾值、數字等)在内,連函數也是對象。另外,類可以被子類化,而且Scala還提供了基于mixin的組合(mixin-based composition)。
與隻支援單繼承的語言相比,Scala具有更廣泛意義上的類重用。Scala允許定義新類的時候重用“一個類中新增的成員定義(即相較于其父類的差異之處)”。Scala稱之為mixin類組合。
Scala還包含了若幹函數式語言的關鍵概念,包括高階函數(Higher-Order Function)、局部套用(Currying)、嵌套函數(Nested Function)、序列解讀(Sequence Comprehensions)等等。
Scala是靜态類型的,這就允許它提供泛型類、内部類、甚至多态方法(Polymorphic Method)。另外值得一提的是,Scala被特意設計成能夠與Java和.NET互操作。Scala目前版本還不能在.NET上運作(雖然上一版可以-_-b),但按照計劃将來可以在.NET上運作。
Scala可以與Java互操作。它用scalac這個編譯器把源檔案編譯成Java的class檔案(即在JVM上運作的位元組碼)。你可以從Scala中調用所有的Java類庫,也同樣可以從Java應用程式中調用Scala的代碼。用David Rupp的話來說,
它也可以通路現存的數之不盡的Java類庫,這讓(潛在地)遷移到Scala更加容易。
這讓Scala得以使用為Java1.4、5.0或者6.0編寫的巨量的Java類庫和架構,Scala會經常性地針對這幾個版本的Java進行測試。Scala可能也可以在更早版本的Java上運作,但沒有經過正式的測試。Scala以BSD許可釋出,并且數年前就已經被認為相當穩定了。
說了這麼多,我們還沒有回答一個問題:“為什麼我要使用Scala?”Scala的設計始終貫穿着一個理念:
創造一種更好地支援元件的語言。(《The Scala Programming Language》,Donna Malayeri)
也就是說軟體應該由可重用的部件構造而成。Scala旨在提供一種程式設計語言,能夠統一和一般化分别來自面向對象和函數式兩種不同風格的關鍵概念。
藉着這個目标與設計,Scala得以提供一些出衆的特性,包括:
- 面向對象風格
- 函數式風格
-
更高層的并發模型
Scala把Erlang風格的基于actor的并發帶進了JVM。開發者可以利用Scala的actor模型在JVM上設計具伸縮性的并發應用程式,它會自動獲得多核心處理器帶來的優勢,而不必依照複雜的Java線程模型來編寫程式。
-
輕量級的函數文法
o 高階
o 嵌套
o 局部套用(Currying)
o 匿名
-
與XML內建
o 可在Scala程式中直接書寫XML
o 可将XML轉換成Scala類
-
與Java無縫地互操作
Scala的風格和特性已經吸引了大量的開發者,比如Debasish Ghosh就覺得:
我已經把玩了Scala好一陣子,可以說我絕對享受這個語言的創新之處。
總而言之,Scala是一種函數式面向對象語言,它融彙了許多前所未有的特性,而同時又運作于JVM之上。随着開發者對Scala的興趣日增,以及越來越多的工具支援,無疑Scala語言将成為你手上一件必不可少的工具。
Scala與Groovy的對比
一篇名為“Scala,Groovy的殺手? ”的部落格對Scala和Groovy進行了對比:
Scala和Groovy之間的核心差別在于前者是靜态類型的。有些人可能争辯說這使得達到腳本化目标變得更加複雜了,而腳本化正是Groovy的動機。然而,Scala有完整的體系特征,這使Groovy看上去更像個玩具。比如,Scala有“sequence comprehensions”。該要素導緻對算法的表述非常緊湊和強大。
Scala還有更多被證明是非常有用的特性,如嵌套類,currying和代數類型模式比對。它還支援類似于JDK1.5所增加的泛型和注解。這些還都隻是冰山一角。
之後,Derek Young撰文“Scala對比Groovy:靜态類型是性能的關鍵”。在文中他舉了一個實際的例子,試圖說明針對同樣的算法,Scala的性能遠高于Groovy。
然而,Scala并不是盡善盡美的,它也有一些明顯的缺陷。Rick Hightower在發表的一篇部落格中,尖銳地批評了Scala的文法問題:
Scala并不是更好的選擇。在閱讀了Scala的文檔之後,我的想法是:雖然這種語言的特性聽起來挺好,但是文法卻讓我想放棄。為什麼事情非要為了不同而不同?Scala讓Groovy看起來比以前更加美味可口。
憎恨是個很強烈的詞。我恨Scala的文法。請不要再推進這種文法了。……Scala有好的思想嗎?有。借用過來就行了……
總而言之,Scala看起來像下一個被過度宣傳的語言。隻需要把其精華引入到Groovy中,然後扔掉那些糟糕的文法。我最喜歡的Scala特性是推理類型和強類型。C#3.0也有這些。(我不用C#,不見得我不喜歡它的一些特性。)
Rick Hightower還建議Sun應該在Groovy上進行投資,而不是對JRuby作無謂的投資。
Groovy更像Java,更容易上手,文法也讓開發者不反感。為什麼Sun在JRuby上投那麼多錢呢?
投資應該給Groovy。這樣了解Java的開發者可以更快地學習Groovy,而且如果有工具支援他們,那麼就更可能這樣做。
為了說明Sun投資在Ruby上的不明智,Rick Hightower還引用了一幅統計圖表來說明企業采用Ruby的趨勢還是比較低的:
圖1
另外,無論是Ruby、Scala還是Groovy都有對應的Web架構,且對應的架構都是用各自對應的語言編寫的。這些架構分别是Rails、Lift和Grails。盡管Lift和Grails中的許多東西都從Rails借鑒來的,但是Grails對其他已有Java技術架構進行了很好的繼承,這無疑會保護使用者或廠商在這方面的已有投資。Grails架構參考文檔中這樣描述:
Grails建構在這些概念之上,并且顯著地減少了在Java平台上建構Web應用的複雜程度。不同的是,這些是建立在已确立的如Spring和Hibernate這樣的Java技術之上的。
Scala和Groovy兩種語言都在快速發展的過程中。就情況來看,Groovy的優勢在于易用性以及與Java無縫銜接,Scala的優勢在于性能和一些進階特性,如果在發展過程中兩者能互相借鑒對方的優點來充實自身,對開發者來講無疑是福音。正如第一篇所引用的部落格作者最後提到的那樣:
大家并不想看到一場殊死鬥争,而是想看到更注重實效思想的Groovy團隊能與更具有學術思想的Scala團隊一起合作,制作出一門既強大又易用的語言。
你會将賭注押在誰身上呢?
Scala 發音為 /ˈskɑːlə, ˈskeɪlə/)是一種多範式的程式設計語言,設計意圖是要內建面向對象程式設計和函數式程式設計的各種特性。
技巧
1、不要陷入C++一樣的、不斷膨脹的問題裡,留下太多的選擇,且沒有清晰的最佳實踐。這導緻每個人都在選擇不同的子集。要提供适應的指導。
2、記住,反對不良的設計功能與增加新功能同等重要——這很殘酷。
3、考慮拆分語言為生産環境建立可行的标準。為學術世界節省成本是一個明智的選擇。迎合企業的需要,獲得更大的采用。
4、庫的編寫者應該看看Java API,确認是否應該有功能調用或結構化功能,為了更好的閱讀。不要為了流動性在跳躍太大來與Ruby競争。
5、最後,當人們提出的建設性的批評時,不要感到失望。如果同樣的報怨不斷出現,那就說明應該重視一下。 [3]
平台和許可證
Scala運作于Java平台(Java虛拟機),并相容現有的Java程式。它也能運作于Java ME, CLDC(Java Platform, Micro Edition Connected Limited Device Configuration)上。還有另一.NET平台的實作,不過該版本更新有些滞後。
Scala的編譯模型(獨立編譯,動态類加載)與Java和C#一樣,是以Scala代碼可以調用Java類庫(對于.NET實作則可調用.NET類庫) 。
Scala包中包含了編譯器和類庫,以BSD許可證釋出。
發展曆史編輯
聯邦理工學院洛桑(EPFL)的Martin Odersky于2001年基于Funnel的工作開始設計Scala。Funnel是把函數式程式設計思想和Petri網相結合的一種程式設計語言。Odersky先前的工作是Generic Java和javac(Sun Java編譯器)。Java平台的Scala于2003年底/2004年初釋出。.NET平台的Scala釋出于2004年6月。該語言第二個版本,v2.0,釋出于2006年3月。
截至2009年9月,最新版本是版本2.7.6 。Scala 2.8預計的特性包括重寫的Scala類庫(Scala collections library)、方法的命名參數和預設參數、包對象(package object),以及Continuation.
2009年4月,Twitter宣布他們已經把大部分後端程式從Ruby遷移到Scala,其餘部分也打算要遷移。此外, Wattzon已經公開宣稱,其整個平台都已經是基于Scala基礎設施編寫的。
特性
面向對象特性
Scala是一種純面向對象的語言,每一個值都是對象。對象的資料類型以及行為由類和特征(Trait)描述。類抽象機制的擴充有兩種途徑。一種途徑是子類繼承,另一種途徑是靈活的混入(Mixin)機制。這兩種途徑能避免多重繼承的種種問題。 [4]
函數式程式設計
Scala也是一種函數式語言,其函數也能當成值來使用。Scala提供了輕量級的文法用以定義匿名函數,支援高階函數,允許嵌套多層函數,并支援柯裡化 。Scala的Case Class及其内置的模式比對相當于函數式程式設計語言中常用的代數類型(Algebraic Type)。 [4]
更進一步,程式員可以利用Scala的模式比對,編寫類似正規表達式的代碼處理XML資料。在這些情形中,順序容器的推導式(comprehension)功能對編寫公式化查詢非常有用。
由于JVM不支援尾部遞歸,Scala也不能完全支援尾部遞歸優化。不過,在簡單的情況下,Scala編譯器可以把尾部遞歸優化成循環。
以下代碼以函數式風格實作了快速排序算法,可以與Erlang快速排序的例子做個比較:
def qsort(list: List[Int]): List[Int]=
list match{
case Nil => Nil
case pivot::tail =>
qsort(for(i <- tail if i < pivot)yield i)::: pivot :: qsort(for(i <- tail if i >= pivot)yield i)
}
靜态類型
Scala是具備類型系統,通過編譯時的檢查,保證代碼的安全性和一緻性。類型系統具體支援以下特性:
泛型類,型變注釋(Variance Annotation),類型繼承結構的上限和下限,把類别和抽象類型作為對象成員,複合類型,引用自己時顯式指定類型,視圖,多态方法。 [4]
擴充性
Scala的設計承認一個事實,即在實踐中,某個領域特定的應用程式開發往往需要特定于該領域的語言擴充。Scala提供了許多獨特的語言機制,可以以庫的形式輕易無縫添加新的語言結構:
任何方法可用作字首或字尾操作符,可以根據預期類型自動構造閉包。聯合使用以上兩個特性,使你可以定義新的語句而無須擴充文法也無須使用宏之類的元程式設計特性。 [4]
使用Scala的架構
Lift是一個開源的Web應用架構,旨在提供類似Ruby on Rails的東西。因為Lift使用了Scala,是以Lift應用程式可以使用所有的Java庫和Web容器。
測試
以下是測試Scala代碼的一些方式:
ScalaTest ScalaCheck,類似于Haskell的QuickCheck的一個庫specs,一個用于Scala的行為驅動的開發工具庫JUnit内置的Scala庫SUnit已經不贊成使用,将會在2.8.0版中移除,見SUnit文檔。
範例
以下是用Scala編寫的典型的Hello Scala中文程式:
object HelloScalachina extends Application { println(“Hello, Scala中文!”)}
或
object HelloScalachina {def main(args: Array[String]){ println(“Hello, Scala中文!”)}}
請注意它與Java的Hello Scala中文應用程式有哪些相似之處。一個顯著差別在于,Scala版的Hello Scala中文程式沒有把任何東西标記為static,而是用object 關鍵字建立了一個單件。
假設該程式儲存為HelloScalachina.scala檔案,接下來可以通過以下指令行進行編譯:
scalac HelloScalachina.scala
若要運作:
scala -classpath . HelloScalachina
這與編譯和運作Java的“Hello Scala中文”程式是不是很像呢?事實上,Scala的編譯和執行模型與Java是等效的,因而它也相容于Java的建構工具,比如Ant.
直接使用Scala解釋器也可以運作該程式,使用選項-i (從檔案加載代碼)和選項-e (若要運作額外的代碼,就得實際執行HelloScalachina對象的方法)即可:
scala -i HelloScalachina.scala -e ‘HelloScalachina.main(null)’