1. 程式人生 > >Scala詳解---------Scala是什麼?可伸展的語言!

Scala詳解---------Scala是什麼?可伸展的語言!

Scala是什麼

Scala語言的名稱來自於“可伸展的語言”。之所以這樣命名,是因為他被設計成隨著使用者的需求而成長。你可以把Scala應用在很大範圍的程式設計任務上,從寫個小指令碼到建立個大系統。

Scala是很容易進入的語言。它跑在標準的Java平臺上,可以與所有的Java庫實現無縫互動。它也是用來編寫指令碼把Java控制元件鏈在一起的很好的語言。但是用它來建立大系統和可重用控制元件的架構將更能夠發揮它的力量。

從技術層面上來說,Scala是一種把面向物件和函數語言程式設計理念加入到靜態型別語言中的混血兒。Scala的許多不同的方面都展現了面向物件和函數語言程式設計的熔合;或許它比其他那些廣泛使用的語言更有滲透性。在可伸展性方面,這兩種程式設計風格具有互補的力量。Scala的函數語言程式設計使得它便於快速地從簡單的碎片開始建立一些有趣的東西。它的面向物件特性又使它便於構造大型系統並使它們適應於新的需求。Scala中這兩種風格的組合使得它有可能表達新的程式設計模式和控制元件抽象。併產生了易讀、簡潔的程式設計風格。由於它良好的延展性,用Scala程式設計將會有很多的樂趣。

不同尺寸的程式傾向於需要不同的程式設計結構。舉例來說,考慮以下的Scala程式:

  1. var capital = Map("US"->"Washington""France" -> "Paris")  
  2. capital += ("Japan" -> "Tokyo")  
  3. println(capital("France")) 

這段程式建立了一個國家和它們的首都之間的對映表,增加了一個新的繫結("Japan"->"Tokyo"),然後列印了與法國相關的首都。 本例中的宣告都是高層次的,也就是說,沒有被外加的分號或者型別註釋弄得亂糟糟的。實際上,這種感覺就好像那種現代的“指令碼化”語言,比如,Perl,Python或者Ruby。這些語言的一個普遍特徵,與上例有關的,就是它們都在語法層面上支援“關聯對映”。

關聯對映非常有用,因為它能讓程式易讀和清晰。然而,有些時候你或許不贊成它們的這種“均碼”哲學,因為你需要用一種更加細粒度地去控制在你程式中用到的對映的屬性。Scala可以在你需要的時候提供這種細粒度的控制,因為對映在Scala裡並不是語法特性。它們是庫抽象,你可以擴充套件或者改造。

在上面的程式裡,你將獲得一個預設的Map實現,不過你也可以很輕鬆地改變它。比方說,你可以定義個特別的實現,如HashMap或TreeMap,或者你可以特定這個對映必須是執行緒安全的,混入:mix-in個SynchronizedMap特色:trait。你還可以給對映特定一個預設值,或你可以過載你建立的對映的任意方法。每個例子裡,你都可以如上例所示那樣使用同樣簡單的對映訪問語法。

這個例子顯示了Scala帶給你的方便性和靈活性,可以讓你更好的瞭解Scala是什麼。Scala有一整套的方便構件來幫助你快速啟動及讓你用一種愉悅清晰的狀態程式設計。與此同時,你有信心你不會讓語言過度發育。你總可以把程式按你的需要裁剪,因為所有的東西都是基於庫模組的,可以依照需要選擇和修改。

Scala是什麼:培育新的型別

Eric Raymond把大教堂和雜貨鋪作為軟體開發的兩個隱喻。 大教堂是幾近於完美的建築物,要花很長的時間建設。一旦建成了,就長時間保持不變。相對來說,雜貨鋪則天天在被工作其中的人調整和擴充套件。Raymond的文章中,雜貨鋪是對於開源軟體開發的隱喻。Guy Steele在他的講話“發展一門語言”中提到同樣的差別也可以應用在語言定義中。 Scala更像一個雜貨鋪而不是大教堂,因為它被設計為讓用它程式設計的人擴充套件和修改的。Scala並沒有提供所有你在一種“完美齊全”語言中可能需要的東西,而是把製作這些東西的工具放在了你的手中。

這兒有個例子。許多程式需要一個能夠變得任意大都不會溢位或者由於數學操作而“繞回”的整數型別。Scala在庫類Scala.BigInt中定義了這樣一個型別。這裡有一個使用了那個型別的方法定義,用以計算傳入整數的階乘值:

  1. def factorial(x: BigInt): BigInt =  
  2. if (x == 01else x * factorial(x - 1

現在,如果你呼叫了factorial(30),你將得到:

265252859812191058636308480000000

BigInt看上去就像一個內建的型別,因為你可以使用整數值和這種型別值的操作符如*和-。然而它只是湊巧定義在Scala標準庫中的類。 如果這個類缺失了,可以直接由任意的Scala程式設計師寫一個實現出來,舉例來說,通過包裝Java的類java.math.BigInteger(實際上,Scala的BigInt就是這麼實現的)。

當然,你也可以直接使用Java的類庫。但結果卻不盡樂觀,因為儘管Java允許建立新的類,但這些類總感覺不像原生的語言支援。

  1. import java.math.BigInteger  
  2. def factorial(x:BigInteger): BigInteger =  
  3. if (x == BigInteger.ZERO)  
  4.         BigInteger.ONE  
  5. else
  6.         x.multiply(factorial(x.subtract(BigInteger.ONE))) 

BigInt代表了許多其他類似於數字的型別——大十進位制數,複數,分數,置信區間,多項式——諸如此類。一些程式語言原生實現了其中的一些型別。舉例來說,Lisp,Haskell和Python實現了大整數;Fortran和Python實現了複數。但是任何語言想要嘗試同時實現所有的這些抽象型別將很容易變得太大而難以管理。更進一步,即使如果有這樣的語言,總有些應用會使用其他的沒支援的數字型別。所以嘗試在一種語言裡提供所有東西的解決之道不可能很好地伸展。取而代之,Scala允許使用者在他們需要的方向上通過定義易用庫來發展和改造語言,使得這些特性感覺上好像原生語言支援一樣。

培育新的控制結構

前面的例子演示了Scala讓你增加新的型別,使得它們用起來方便得像內建型別一樣。同樣的擴充套件理念也應用在控制結構上。這種型別的擴充套件是由Scala的“基於行動類”的併發程式設計API闡明的。

隨著近年多核處理器的激增,為了獲取可接受的效能,你將必須在應用中運用更多的並行機制。常常這就意味著重寫你的程式碼來讓計算分佈到若干併發執行緒上。不幸的是,建立依賴性的多執行緒程式在實踐中被證明是非常具有挑戰性的。Java的執行緒模型是圍繞著共享記憶體和鎖建立的,尤其是當系統在大小和複雜度都得到提升的時候,這種模型常常是不可理喻的。很難說程式裡面沒有資源競爭或潛藏的死鎖——有些東西不是能在測試裡面檢驗得出,而或許只在投入生產後才表現出來。而大致可以認為比較安全的可選方案是訊息傳遞架構,例如在Erlang程式語言中應用的“行動類”方案。

Java伴隨著一個豐富的,基於執行緒的併發庫。Scala可以像其他JavaAPI那樣使用它程式設計。然而,Scala也提供了一個實質上實現了Erlang的行動類模型的附加庫。

行動類是能夠實現於執行緒之上的併發抽象。它們通過在彼此間傳送訊息實現通訊。每個行動類都能實現兩個基本操作,訊息的傳送和接受。傳送操作,用一個驚歎號表示,傳送訊息給一個行動類。這裡用一個命名為recipient的行動類舉例如下:

  1. recipient ! msg 

傳送是非同步的;就是說,傳送的行動類可以在一瞬間完成,而不需要等待訊息被接受和處理。每一個行動類都有一個信箱:mailbox把進入的訊息排成佇列。行動類通過receive程式碼塊處理信箱中受到的訊息:

  1. receive {  
  2. case Msg1 => ... // handle Msg1
  3. case Msg2 => ... // handle Msg2
  4. // ...
  5. }  

接收程式碼塊由許多case語句組成,每一個都用一個訊息模板查詢信箱。信箱中第一個符合任何case的訊息被選中,並且執行相應的動作。如果信箱中不含有任何符合任何case的訊息,行動類將休眠等待新進的訊息。

這裡舉一個簡單的Scala行動類實現檢查值(cheksum)計算器服務的例子:

  1. actor {  
  2.  var sum = 0
  3.  loop {  
  4.   receive {  
  5. case Data(bytes)  => sum += hash(bytes)  
  6. case GetSum(requester) => requester ! sum  
  7.   }  
  8.  }  
  9. }  

這個行動類首先定義了一個名為sum的本地變數,並賦了初值為零。然後就用receive段落重複等待在訊息迴圈中。如果收到了Data訊息,就把傳送的bytes取雜湊值加到sum變數中。如果收到了GetSum訊息,就用訊息傳送requester!sum把當前sum值發回給requester。requester欄位嵌入在GetSum訊息裡;它通常指出建立請求的行動類。

目前我們並不指望你能完全明白行動類例子。實際上,對於可伸展性這個話題來說這個例子裡面最重要的是,不論是actor還是loop還是receive還是傳送訊息的符號“!”,這些都不是Scala內建的操作符。儘管actor,loop和receive看上去或者表現上都如此接近於控制結構如while或者for迴圈,實際上它們是定義在Scala的行動類庫裡面的方法。同樣,儘管“!”看上去像是個內建的操作符,它也不過是定義在行動類庫裡面的方法。所有這四個構件都是完全獨立於Scala語言的。

receive程式碼塊和傳送“!”語法讓Scala看上去更像Erlang裡的樣子,但是在Erlang裡面,這些構件是內建在語言中的,Scala還實現了Erlang其他併發程式設計構件的大多數,諸如監控失敗行動類和超時類。總體來說,行動類已變成表達併發和分散式計算的非常好的辦法。儘管它們是定義在庫裡的,給人的感覺就像行動類是Scala語言整體的部分。

本例演示了你可以向新的方向“培養”Scala語言乃至像併發程式設計這樣的特性。前提是,你需要一個好的架構和程式設計師來做這樣的事。但重要的事情是這的確可行——你可以在Scala裡面設計和實現抽象結構,從而快速投入新的應用領域,卻仍然感覺像是原生的語言支援。

本文節選自Martin Odersky,Lex Spoon和Bill Venners所著,Regular翻譯的《Programming in Scala》的第一章。

本文借鑑於http://developer.51cto.com/art/200907/134865.htm