Scala學習手冊--可伸縮的語言(隨着使用者的需求而成長) java
第一章:基本概念 程序員
Scala=FP+OO、靜態語言 編程
兼容性、簡短、高層級抽象、高級的靜態類別、伸縮性 api
兼容:與Java兼容,可無縫實施互操做。Scala程序會被編譯爲JVM的字節碼。性能一般一致。Scala能夠調用Java方法,訪問Java字段,繼承自Java類和實現Java接口。實際上,幾乎全部的Scala代碼都極度依賴於Java庫。 數組
交互式操做的另外一面是:Scala極度重用了Java類型,Int-->int,Float-->float,Boolean-->boolean。Scala的數組被映射到Java數組。Scala一樣重用了許多標準Java庫類型。 數據結構
Scala不只重用,並且增長了更多特性或改進,Scala字符串支持相似於toInt,toFloat的方法。 併發
隱式轉換:這一般在類型失配,或許選用不存在的方法時。在上面的例子裏,當在字串中尋找toInt方 異步
法時,Scala 編譯器會發現String 類裏沒有這種方法,但它會發現一個把Java的String ide
轉換爲Scala 的RichString類的一個實例的隱式轉換,裏面定義了這麼個方法。因而在 函數式編程
執行toIn t 操做以前,轉換被隱式應用。
Scala 代碼一樣能夠由Java代碼調用。有時這種狀況要更加微妙,由於Scala 是一種比Java
更豐富的語言,有些Scala 更先進的特性在它們能映射到Java 前須要先被編碼一下。
簡潔:分號可不寫,且一般不寫;類與構造函數的簡寫;類型推斷
class MyClass(index: Int , name: String) //寫得少就不多犯錯誤 |
高層級:業務邏輯的複雜帶來了複雜的代碼,過分複雜又帶來了系統性能或致使崩潰。這種複雜無可避免,因此就須要由不受控轉爲受控。
Scala經過使用接口的抽象級別來幫助你管理複雜性。
函數式文本:
val nameHasUpperCase = name.exists(_.isUpperCase) //判斷String 包含一個大寫字符 |
Scala是靜態類型的:這就容許它提供泛型類、內部類、甚至多態方法(Polymorphic Method)。另外值得一提的是,Scala被特地設計成可以與Java和.NET互操做。
語法輕量級,原語富有表達力,這些能夠從拆分器、組合器和執行器中體現
scala被普遍使用:滲透性、可伸縮性
var capital = Map ("US"->"Washington", "France" -> "Paris") capital += ("Japan" -> "Tokyo") println(capital("France" )) |
本例中的聲明都是高層次的,也就是說,沒有被外加的分號或者類型註釋弄得亂糟糟的。實際上,這種感受就好像那種現代的「腳本化」語言,好比,Perl ,Python或者Ruby。這些語言的一個廣泛特徵,與上例有關的,就是它們都在語法層面上支持「關聯映射」。
方便性和靈活性
關聯映射很是有用,由於它能讓程序易讀和清晰。
Scala更像一個雜貨鋪而不是大教堂,由於它被設計爲讓用它編程的人擴展和修改的。
新的類型
許多程序須要一個可以變得任意大都不會溢出或者因爲數學操做而「繞回」
的整數類型。Scala在庫類Scala.BigInt中定義了這樣一個類型。這裏有一個使用了那個
類型的方法定義,用以計算傳入整數的階乘值:
def factorial(x: BigInt): BigInt = if (x == 0) 1 else x * factorial(x - 1) 調用:factorial(30) 結果:265252859812191058636308480000000 |
BigInt 看上去就像一個內建的類型,由於你可使用整數值和這種類型值的操做符如* 和- 。然而它只是湊巧定義在Scala標準庫中的類。6若是這個類缺失了,能夠直接由任意的Scala程序員寫一個實現出來,舉例來講,經過包裝Java的類java.math.BigInteger(實際上,
Scala的BigInt 就是這麼實現的)。
調用Java API實現:
import java.math.BigInteger def factorial(x:BigInteger): BigInteger = if (x == BigInteger.ZERO) BigInteger.ONE else x.multiply(factorial(x.subtract(BigInteger.ONE)))
|
新的共享/併發程序
Java的線程模型是圍繞着共享內存和鎖創建的,尤爲是當系統在大小和複雜度都獲得提高的時候,這種模型經常是不可理喻的。
Java伴隨着一個豐富的,基於線程的併發庫。Scala 能夠像其餘JavaAPI 那樣使用它編程。
然而,Scala 也提供了一個實質上實現了Erlang的行動類模型的附加庫。
行動類是可以實現於線程之上的併發抽象。它們經過在彼此間發送消息實現通訊。每一個行
動類都能實現兩個基本操做,消息的發送和接受。發送操做,用一個驚歎號表示,發送消
息給一個行動類。這裏用一個命名爲recipient 的行動類舉例以下:
recipient ! msg
發送是異步的;就是說,發送的行動類能夠在一瞬間完成,而不須要等待消息被接受和處
理。每個行動類都有一個信箱:mailbox 把進入的消息排成隊列。行動類經過receive
代碼塊處理信箱中受到的消息:
receive { case Msg1 => ... // handle Msg1 case Msg2 => ... // handle Msg2 // ... } |
接收代碼塊由許多case 語句組成,每個都用一個消息模板查詢信箱。信箱中第一個符
合任何case的消息被選中,而且執行相應的動做。若是信箱中不含有任何符合任何case的消息,行動類將休眠等待新進的消息。
這裏舉一個簡單的Scala 行動類實現檢查值(cheksum)計算器服務的例子:
actor { var sum = 0 loop { receive { case Data(bytes) => sum += hash(bytes) case GetSum(requester) => requester ! sum } } } |
這個行動類首先定義了一個名爲sum 的本地變量,並賦了初值爲零。而後就用receive段
落重複等待在消息循環中。若是收到了Data 消息,就把發送的bytes取哈希值加到sum
變量中。若是收到了GetSum 消息,就用消息發送requester!sum 把當前sum 值發回給
requester。requester 字段嵌入在GetSum 消息裏;它一般指出建立請求的行動類。
實際上,對於可伸展性這個話題來講這個例
子裏面最重要的是,不管是actor仍是loop 仍是receive仍是發送消息的符號「!」,這
些都不是Scala 內建的操做符。儘管actor,loop 和receive 看上去或者表現上都如此接
近於控制結構如while或者for 循環,實際上它們是定義在Scala 的行動類庫裏面的方法。
一樣,儘管「!」看上去像是個內建的操做符,它也不過是定義在行動類庫裏面的方法。
全部這四個構件都是徹底獨立於Scala 語言的。
Scala 具備伸縮性
Scala 在把面向對象和函數式編程熔合成一套語言的設計方面比其餘衆所周知的語言都走
得更遠。比方說,其餘語言或許把對象和方法做爲兩個不一樣的概念,但在Scala 裏,函數
值就是對象。函數類型是可以被子類繼承的類。這看上去彷佛不外乎學術上的美感,但它
從深層次上影響了可伸展性。實際上以前看到的行動類這個概念若是沒有這種函數和對象
的聯合將沒法實現。
Scala函數式編程的主要思想:
第一理念:函數是第一類值,能夠把函數看成參數傳遞給其餘函數,看成結果從函數中返回或保存在變量裏。你也能夠在函數裏定義其餘函數,就好像在函數裏定義整數同樣。還能夠定義匿名函數。
把函數做爲第一類值爲操做符上的抽象和建立新控制結構提供了便利的方法。這種函數的
泛化提供了很強的表現力,常能產生很是易讀和清晰的程序。並且常在伸展性上扮演重要
的角色。例如,以前在行動類例子裏演示的receive構造就是一個把函數看成參數調用的
方法。receive構造裏面的代碼是個未被執行的傳入receive方法的函數。
相反,在多數傳統語言中,函數不是值。確實有函數值的語言則又經常把它們貶爲二類地
位。舉例來講,C 和C++ 的函數指針就不能擁有與非函數指針在語言中同等的地位:函數
指針僅能指向全局函數,它們不容許你定義指向環境中什麼值的第一類嵌套函數,也不能
定義匿名函數文本。
第二理念:程序的操做符應該把輸入值映射到輸出值而不是就地修改數據。
在Java和Scala 裏,字串是一種數學意義上的字符序列。
使用表達式如s.replace(';', '.')在字串裏替換字符會產生一個新的,不一樣於原字串s
的對象。用另外一種表達方式來講就是在 Java裏字串是不可變的(immutable)而在 Ruby
裏是可變的。所以單看字串來講,Java是函數式語言,而 Ruby 不是。不可變數據結構是
函數式語言的一塊基石。Scala 庫在Java API 之上定義了更多的不可變數據類型。例如,
Scala 有不可變的列表,元組,映射表和集。
第三理念:方法不該有任何反作用:side effect。它們惟一的與所在環境交流的方式應該是得到參數和返回結果。
舉例來講,Java 的String 類的replace 方法符合這個描述。它帶一個字串和兩個字符併產生一個全部一個字符都被另外一個替代掉的新字串。調用replace不會有其餘的結果。相似於 replace這樣的方法被稱爲指稱透明:referentially transparent ,就是說方法調用對任何給定的輸入能夠用它的結果替代而不會影響程序的語義。
函數式語言鼓勵不可變數據結構和指稱透明的方法。有些函數式語言甚至須要它們。Scala給你選擇。若是你須要,你也能夠寫成命令:imperative 形式,用可變數據和有反作用的方法調用編程。可是Scala 一般能夠在你須要的時候輕鬆避免它們,由於有好的函數式編程方式作替代。
第二章、語法學習
1.變量:聲明變量可使用val和var,val相似於java裏的final變量,一旦初始化就不可變;var如同java裏的非final變量,能夠在其生命週期內屢次賦值。
類型推導:type inference,理解你省略的類型的能力。
函數及返回值縮寫規則:
1:能夠不寫返回值,由編譯器自動推導 2:若是函數方法體能夠用一個句子組成,能夠省略{} 如:scala> def max2(x: Int , y: Int ) = if (x > y) x else y 3:函數不帶參數也沒有返回值,好比:
greet表示函數名,()表示參數特色--不帶參數,Unit是greet的結果類型(在Java裏被認爲是返回值),Unit表示函數沒有返回有用戶的值(實際上scala裏的Unit會被編譯器映射爲Java裏的void)。
|
循環:
while循環
var i = 0 while (i < args.length) { println(args(i)) i += 1 //scala只支持i+=1或者i=i+1,不支持i++/++i自增操做 }
var r=0; var i=1; while(i<100){r+=i*i;i+=2}; |
foreach和for枚舉