讀《快學(xué)Scala 》一書(shū)的摘要
Scala 運(yùn)行于JVM之上,擁有海量類(lèi)庫(kù)和工具镊讼,兼顧函數(shù)式編程和面向?qū)ο蟆?/p>
在Scala中宽涌, 解釋器就是我們喜歡的REPL,變量或者函數(shù)的類(lèi)型總是寫(xiě)在變量或函數(shù)的后面(與java相反)蝶棋,數(shù)值類(lèi)型的轉(zhuǎn)換通過(guò)方法而不是強(qiáng)制類(lèi)型轉(zhuǎn)換卸亮,僅當(dāng)同一行代碼存在多條語(yǔ)句時(shí)才需要用分號(hào)隔開(kāi)。
scala 允許自定義操作符玩裙,注意有分寸地使用兼贸,在使用scala.開(kāi)頭的包時(shí),可以省去scala前綴吃溅。scala沒(méi)有靜態(tài)方法溶诞,類(lèi)似的特性可以用單例對(duì)象,一個(gè)類(lèi)對(duì)應(yīng)的companion object就跟Java中的靜態(tài)方法一樣罕偎,使用companion object的apply方法是scala中構(gòu)建對(duì)象的常用方法很澄。
控制
在scala中,判斷語(yǔ)句跟其他語(yǔ)言類(lèi)似颜及,但{}塊包含一系列表達(dá)式甩苛,其結(jié)果也是一個(gè)表達(dá)式,塊中最后一個(gè)表達(dá)式的值就是塊的值俏站。
在for 循環(huán)的變量之前并沒(méi)有val或var的指定讯蒲。該變量的類(lèi)型是集合的元素類(lèi)型,循環(huán)變量的作用域一直持續(xù)到循環(huán)結(jié)束肄扎。scala并沒(méi)有提供break或continue語(yǔ)句來(lái)退出循環(huán)墨林,替代方法如下:
- 使用Boolean的控制變量
- 使用嵌套函數(shù)——在函數(shù)中return
- 使用Breaks對(duì)象中的break方法赁酝,控制權(quán)的轉(zhuǎn)移是通過(guò)拋出和捕獲異常完成的,出于性能考慮旭等,盡量避免這一機(jī)制酌呆。
for有豐富的形態(tài),可以提供多個(gè)生成器搔耕,并帶有if開(kāi)頭的表達(dá)式隙袁,還可以使用任意多的循環(huán)變量定義。
函數(shù)
scala中的方法對(duì)對(duì)象進(jìn)行操作弃榨,而函數(shù)不是菩收,C++中也有函數(shù),不過(guò)在Java中智能用靜態(tài)方法模擬鲸睛,scala的函數(shù)不需要return娜饵,對(duì)應(yīng)遞歸函數(shù)必須指明返回類(lèi)型,可以混用未命名參數(shù)和帶名參數(shù)官辈,只要那些未命名的參數(shù)是排在前面的即可箱舞。
同樣,變長(zhǎng)參數(shù)列表很方便拳亿,通過(guò) :_* 將值序列轉(zhuǎn)換成參數(shù)序列褐缠。當(dāng)變長(zhǎng)參數(shù)類(lèi)型為Object的Java方法時(shí),需要手工對(duì)基本類(lèi)型進(jìn)行轉(zhuǎn)換风瘦。
scala對(duì)不返回值的函數(shù)有特殊的表示法,如果函數(shù)體包含在花括號(hào)當(dāng)中但沒(méi)有前面的=號(hào)公般,那么返回類(lèi)型就是Unit万搔,這樣的函數(shù)也叫過(guò)程函數(shù)。
當(dāng)val 被聲明為lazy時(shí)官帘,它的初始化將被延遲加載瞬雹,直到對(duì)它初次取值。每次訪(fǎng)問(wèn)延遲加載的變量刽虹,都會(huì)有一個(gè)方法被調(diào)用酗捌,以線(xiàn)程安全的方式檢查該值是否已被初始化。
異常
scala異常的工作機(jī)制和Java或C++一樣涌哲,但沒(méi)有"受檢"異常胖缤,捕獲異常采用模式匹配的語(yǔ)法,不需要使用捕獲的異常對(duì)象阀圾,可以用_來(lái)替代變量名哪廓。try/catch和try/finally是互補(bǔ)的。
數(shù)組和映射
Scala中的Array是定長(zhǎng)數(shù)組初烘,ArrayBuffer是變長(zhǎng)數(shù)組涡真,對(duì)應(yīng)于Java中的ArrayList分俯,C++中的Vector,可以用相同的代碼處理這兩種數(shù)據(jù)結(jié)構(gòu)哆料,用 for (i<-區(qū)間 )來(lái)遍歷缸剪,
用for(...) yield
創(chuàng)建一個(gè)類(lèi)型與原始集合相同的新集合,還可以通過(guò)if 在進(jìn)行條件過(guò)濾东亦。Scala中的內(nèi)建函數(shù)sum杏节,sorted,max讥此,min拢锹,quicksork提供了常用算法。由于Scala數(shù)組是用java數(shù)組實(shí)現(xiàn)的萄喳,可以在java和scala之間傳遞卒稳,只需引入scala.collection.JavaConversions里的隱式轉(zhuǎn)換方法。
scala中他巨,映射是對(duì)偶的集合,可以看做將鍵映射到值的函數(shù)充坑,區(qū)別在于函數(shù)一般用于計(jì)算,而映射只做查詢(xún)染突。用=可以直接增加映射捻爷,也可用+=添加多個(gè)關(guān)系,用for((k,v)<-映射) 來(lái)遍歷映射份企,使用scala.collection.JavaConversions.mapAsScalaMap將Java中的map轉(zhuǎn)換為scala中的映射也榄。
scala中,元組是不同類(lèi)型的值的聚集司志,()構(gòu)成元組甜紫,用方法1,2...訪(fǎng)問(wèn)其組元,而通常使用模式匹配來(lái)獲取元組的組元骂远。使用元組的原因之一是把多個(gè)值綁在一起囚霸,以便它們能夠被一起處理,通常用zip方法開(kāi)完成激才,使用toMap方法將對(duì)偶的集合轉(zhuǎn)換成映射拓型。
類(lèi)與對(duì)象
在scala中,類(lèi)并不聲明為public瘸恼,源文件可以包含多個(gè)類(lèi)劣挫,所有這些類(lèi)都具有共有可見(jiàn)性。對(duì)每個(gè)字段都提供了getter和setter方法东帅,分別叫做 字段名 和 字段名_,可重新自定義揣云。
注意:
1)如果字段私有,則getter和setter也是私有的
2)如果字段val冰啃,則只有g(shù)etter方法
3)如果不需任何getter和setter邓夕,可將字段聲明為private[this]
將scala字段標(biāo)注為@BeanProperty時(shí)刘莹,會(huì)產(chǎn)生Java屬性的定義方法getxxx和setxxx。
scala中的類(lèi)有一個(gè)主構(gòu)造器primary constructor焚刚,可有任意多個(gè)輔助構(gòu)造器 auxiliary constructor点弯。輔助構(gòu)造器與其他語(yǔ)言的區(qū)別在于: 1)名稱(chēng)為this 2)必須以一個(gè)先前已定義的其他輔助構(gòu)造器或主構(gòu)造器的調(diào)用開(kāi)始。而主構(gòu)造器的參數(shù)直接放置在類(lèi)名之后矿咕,會(huì)執(zhí)行類(lèi)定義中的所有語(yǔ)句抢肛,無(wú)參主構(gòu)造器僅僅執(zhí)行類(lèi)體中的所有語(yǔ)句而已。如果將主構(gòu)造器定義為私有的碳柱,則必須通過(guò)輔助構(gòu)造器來(lái)構(gòu)造對(duì)象了捡絮。在內(nèi)嵌類(lèi)中,可以通過(guò)外部類(lèi).this來(lái)訪(fǎng)問(wèn)外部類(lèi)的this 引用莲镣。
對(duì)象本質(zhì)上擁有類(lèi)的所有特質(zhì)福稳,只不能提供構(gòu)造器參數(shù)。所有使用單例對(duì)象的地方瑞侮,scala中都可以用對(duì)象來(lái)實(shí)現(xiàn)的圆。
1)作為存放工具函數(shù)或常量的地方
2)高效共享單個(gè)不可變實(shí)例
3)需要用單個(gè)實(shí)例來(lái)協(xié)調(diào)某個(gè)服務(wù)時(shí)
對(duì)Java中既有實(shí)例方法又有靜態(tài)方法的類(lèi),scala通過(guò)類(lèi)及與類(lèi)同名的伴生對(duì)象來(lái)實(shí)現(xiàn)半火。類(lèi)和它的伴生對(duì)象可以相互訪(fǎng)問(wèn)私有特性越妈,必須存在于同一源文件中。
每個(gè)scala程序都必須從一個(gè)對(duì)象的main方法開(kāi)始钮糖,也可以擴(kuò)展App特質(zhì)梅掠。scala中沒(méi)有枚舉類(lèi)型,但標(biāo)準(zhǔn)類(lèi)庫(kù)提供了一個(gè)Enumeration助手類(lèi)店归,用于產(chǎn)生枚舉瓤檐。
包
Scala中的包與java包或c++命名空間的目的相同,但可以在同一文件中為多個(gè)包貢獻(xiàn)內(nèi)容娱节。
盡量使用完整包名,避免使用scala,java,com,org等來(lái)命名嵌套的包祭示。串聯(lián)式包語(yǔ)句可以限定可見(jiàn)的包肄满。
包可以包含類(lèi),對(duì)象和屬性质涛,但不能包含函數(shù)和變量的定義稠歉,在實(shí)現(xiàn)上,包對(duì)象被編譯成帶有靜態(tài)方法和字段的JvM類(lèi)汇陆。通過(guò)修飾符同樣可以達(dá)到public怒炸,private或protected的效果。
在scala中毡代, 任何地方都可以聲明引入包阅羹,這一點(diǎn)和python很相似勺疼。通過(guò)選取器可以引入包中的指定成員,還可以對(duì)指定成員重命名或者隱藏java.lang,scala,predef 總是被默認(rèn)引入的捏鱼。
繼承
scala擴(kuò)展類(lèi)的方式同樣是使用extends關(guān)鍵字执庐,重寫(xiě)一個(gè)非抽象方法必須使用override修飾符,用isInstanceOf方法判斷某個(gè)對(duì)象是否屬于某個(gè)特定的類(lèi)导梆,只有主構(gòu)造器可以調(diào)用超類(lèi)的構(gòu)造器轨淌。
字段重寫(xiě)時(shí)的限制:
- def 只能重寫(xiě)另一個(gè)def
- 只能重寫(xiě)另一個(gè)val或不帶參數(shù)的def
- var只能重寫(xiě)另一個(gè)抽象的var
構(gòu)造順序問(wèn)題的根本原因——java允許在超類(lèi)的構(gòu)造方法中調(diào)用子類(lèi)的方法。因?yàn)樵谧宇?lèi)中正確的擴(kuò)展相等性判斷非常困難看尼,所以將equals方法定義成final递鹉。除非萬(wàn)不得已,不要使用wait藏斩,notify和synchronized躏结。
和java的接口不同,scala特質(zhì)可以給出這些特質(zhì)的缺省實(shí)現(xiàn)灾茁。讓特質(zhì)擁有具體行為存在一個(gè)弊端窜觉,當(dāng)特質(zhì)改變時(shí),所有混入了該特質(zhì)的類(lèi)必須要重新編譯北专。scala不支持多繼承禀挫,可以用with關(guān)鍵字來(lái)添加額外的特質(zhì)。當(dāng)做富接口使用的特質(zhì)將具體方法和抽象方法結(jié)合在了一起拓颓,特質(zhì)中的字段同樣既可以是具體的语婴,又可以是抽象的。
混入特質(zhì)的對(duì)象在構(gòu)造時(shí)的執(zhí)行順序:
- 首先調(diào)用超類(lèi)的構(gòu)造器
- 特質(zhì)構(gòu)造器在超類(lèi)構(gòu)造器之后驶睦,類(lèi)構(gòu)造器之前執(zhí)行
- 特質(zhì)由左到右構(gòu)造
- 每個(gè)特質(zhì)中砰左,父特質(zhì)先被構(gòu)造,
- 如果多個(gè)特質(zhì)有一個(gè)父特質(zhì)场航,若已被構(gòu)造則不會(huì)再次構(gòu)造
- 所有特質(zhì)構(gòu)造完畢缠导,子類(lèi)被構(gòu)造。
缺少構(gòu)造器參數(shù)是特質(zhì)與類(lèi)之間唯一的技術(shù)差別溉痢。
文件訪(fǎng)問(wèn)
scala.io.source對(duì)象的getlines方法可以讀取文件的所有行僻造,可以把source對(duì)象當(dāng)成迭代器讀取文件中的每個(gè)字符,java.util.Scanner來(lái)處理同事包含文本和數(shù)字的文件孩饼。
從URL中讀取時(shí)髓削,需要事先知道編碼格式,scala中沒(méi)有提供讀取二進(jìn)制文件的方法镀娶,需要使用Java類(lèi)庫(kù),同樣沒(méi)有內(nèi)建的對(duì)寫(xiě)入文件的支持立膛,可使用java.io.PrintWriter,訪(fǎng)問(wèn)目錄也要用java的方法,例如java.nio.file.Files類(lèi)中的walkFileTree梯码。
scala集合類(lèi)都是可序列化的宝泵。
scala.sys.process包提供了用于與shell程序交互的工具好啰,包含了一個(gè)從字符串到processbuilder對(duì)象的隱式轉(zhuǎn)換,鲁猩!操作符就是執(zhí)行這個(gè)processbuidler的對(duì)象坎怪。scala.util.matching.Regex 利用正則表達(dá)式對(duì)字符串進(jìn)行分析。
操作符與解析器
變量廓握、函數(shù)搅窿、類(lèi)等的名稱(chēng)統(tǒng)稱(chēng)為標(biāo)識(shí)符,反引號(hào)中可以包含幾乎任何字符序列隙券。
在scala中男应,除了
- 以冒號(hào):結(jié)尾的操作符
- 賦值操作符
所有操作符都是左結(jié)合的。
unapply方法接受一個(gè)對(duì)象娱仔,然后從中取值沐飘,通常是當(dāng)初用來(lái)構(gòu)造該對(duì)象的值。要取任意長(zhǎng)度的值的序列牲迫,一般用unapplySeq命名方法耐朴。
Scala解析器庫(kù)是scala語(yǔ)言總內(nèi)嵌領(lǐng)域特定語(yǔ)言(DSL)的高級(jí)示例。為了使用Scala解析庫(kù)盹憎,需提供一個(gè)擴(kuò)展自Parsers特質(zhì)的類(lèi)并定義那些由基本操作組合起來(lái)的解析操作筛峭,包括:
- 匹配一個(gè)詞法單元
- 在兩個(gè)操作之間做選擇(|)
- 依次執(zhí)行兩個(gè)操作(~)
- 重復(fù)一個(gè)操作(rep)
- 可選擇地執(zhí)行一個(gè)操作(opt)
組合子返回的是樣例類(lèi)的實(shí)例而不是對(duì)偶,這樣更方便模式匹配陪每。要生成解析樹(shù)影晓,需用^^操作符,給出產(chǎn)生樹(shù)節(jié)點(diǎn)的函數(shù)檩禾,避免左遞歸和回溯挂签。
StandardTokenParsers類(lèi)提供了一個(gè)產(chǎn)出這些詞法單元的解析器。
集合
Scala中所有集合都是iterable的盼产,seq是有先后次序的序列(如數(shù)組和列表)饵婆,Set是沒(méi)有先后次序的序列,map是一種鍵值對(duì)偶戏售。Scala優(yōu)先采用不可變集合侨核,::操作符從給定的頭和尾創(chuàng)建一個(gè)新的列表。如果要把列表中的某個(gè)節(jié)點(diǎn)變成列表中的最后一個(gè)節(jié)點(diǎn)蜈项,不能將next引用設(shè)為nil,而應(yīng)該設(shè)為L(zhǎng)inkedList.empty.
已排序的集使用紅黑樹(shù)實(shí)現(xiàn)的续挟,scala2.9沒(méi)有可變的已排序集紧卒,要用到j(luò)ava.util.TreeSet
Scala 關(guān)于添加和移除的操作符:
- 向后
(:+)
或向前(+:)
追加元素到序列中 - 添加
(+)
元素到無(wú)先后次序的集合中 - 用
-
移除元素 - 用
++
和--
批量添加和移除元素 - 對(duì)于列表,優(yōu)先使用
::
和:::
- 改值操作有
+=
诗祸,++=
跑芳,-=
和--=
對(duì)于集合轴总,推薦++,&和--博个,盡量不用++:怀樟,+=:和++=: 操作方式。
初始值和操作符是兩個(gè)分開(kāi)定義的柯里化參數(shù)盆佣,這樣scala就能用初始值類(lèi)型來(lái)推斷操作符的類(lèi)型定義往堡。任何while循環(huán)都可以用折疊來(lái)替代,對(duì)于那些完整構(gòu)造需要很大開(kāi)銷(xiāo)的集合而言共耍,迭代器作用大虑灰,而流將緩存訪(fǎng)問(wèn)過(guò)的行,允許你重新訪(fǎng)問(wèn)他們痹兜。
對(duì)于數(shù)組穆咐,緩存,哈希表字旭,平衡樹(shù)而言对湃,基于par方法的并行實(shí)現(xiàn)很高效。
模式匹配
與switch語(yǔ)句不同遗淳,scala模式匹配沒(méi)有break的問(wèn)題拍柒。如果case中的判斷不能匹配,則捕獲所有的模式來(lái)嘗試匹配洲脂。變量模式可能與常量表達(dá)式?jīng)_突斤儿,變量必須以小寫(xiě)字母開(kāi)頭。如果有一個(gè)小寫(xiě)字母開(kāi)頭的常量恐锦,則需要把它抱在反引號(hào)中往果。
在類(lèi)型匹配的時(shí)候,必須給出一個(gè)變量名一铅,否則會(huì)拿對(duì)象本身來(lái)進(jìn)行匹配陕贮。由于匹配發(fā)生在運(yùn)行時(shí),Jvm中泛型的類(lèi)型信息是被擦掉的潘飘,所有不能用類(lèi)型來(lái)匹配特定的Map類(lèi)型肮之。正則表達(dá)式是適合使用提取器的場(chǎng)景。
樣例類(lèi)是一種特殊的類(lèi)卜录,經(jīng)過(guò)優(yōu)化以被用于模式匹配戈擒,其實(shí)例使用(),樣例對(duì)象不使用圓括號(hào)艰毒。中置表示法可用于任何返回對(duì)偶的unapply方法筐高。樣例類(lèi)的特點(diǎn):
- 模式匹配的代碼更精簡(jiǎn)
- 構(gòu)造時(shí)不需new
- 可以免費(fèi)得到toString,equals,hashCode 和copy方法
讓所有樣例類(lèi)都擴(kuò)展某個(gè)密封的類(lèi)或特質(zhì)是個(gè)好做法。被包在花括號(hào)內(nèi)的一組case語(yǔ)句是一個(gè)偏函數(shù)柑土,偏函數(shù)表達(dá)式必須位于編譯器可以推斷返回類(lèi)型的上下文中蜀肘。
注解
注解可以在程序的各個(gè)條目中添加信息,是插入到代碼中以便有工具可以對(duì)他們進(jìn)行處理的標(biāo)簽稽屏“绯瑁可以對(duì)是scala類(lèi)使用java注解,也可以使用scala特有的注解狐榔。
在scala中坛增,可為類(lèi),方法荒叼,字段轿偎,局部變量和參數(shù)添加注解。Java注解的參數(shù)類(lèi)型只能是:
- 數(shù)值型變量
- 字符串
- 類(lèi)變量
- java枚舉
- 其他注解
- 上述類(lèi)型的數(shù)組被廓。
如果要實(shí)現(xiàn)一個(gè)新的Java注解坏晦,則需要用Java來(lái)編寫(xiě)該注解類(lèi)。scala用@clonable和@remote來(lái)標(biāo)記可被克隆的和遠(yuǎn)程的對(duì)象嫁乘。@varargs注解可以從Java調(diào)用Scala的帶有變長(zhǎng)參數(shù)的方法昆婿。
Scala類(lèi)庫(kù)中的有些注解可以控制編譯器的優(yōu)化,@tailrec 用于消除遞歸蜓斧,@switch 注解可以檢查scala的match語(yǔ)句是否真的被編譯成了跳轉(zhuǎn)表仓蛆,用@inline來(lái)建議編譯器做內(nèi)聯(lián),@editable給那些可以在生產(chǎn)代碼中移除的方法打上標(biāo)記挎春,對(duì)被省略的方法的調(diào)用看疙,編譯器會(huì)替換成Unit對(duì)象,@uncheckVariance會(huì)取消與型變相關(guān)的錯(cuò)誤提示直奋。
xml處理
Scala提供了對(duì)xml(當(dāng)然也就支持html了)的內(nèi)建支持能庆,可以用scala.xml.Elem的值表示一個(gè)XML元素。Node類(lèi)是所有xml節(jié)點(diǎn)類(lèi)型的父類(lèi)脚线,Elem類(lèi)描述xml元素搁胆。要處理某個(gè)元素的屬性鍵和值,可以用attributes屬性邮绿,然后用()來(lái)訪(fǎng)問(wèn)定鍵的值 渠旁,使用循環(huán)或asAttrMap方法遍歷所有屬性。
內(nèi)嵌的字符串會(huì)被轉(zhuǎn)成Atom[String]節(jié)點(diǎn)船逮,所以可在xml中包含scala代碼顾腊,被內(nèi)嵌的scala代碼還可以繼續(xù)包含XML片段,被引用的字符串當(dāng)中的花括號(hào)不會(huì)被解析和求值挖胃。
NodeSeq提供了類(lèi)似xpath中/,//的操作符杂靶,scala中用,\ 替代承耿,可以在模式匹配中使用xml的關(guān)鍵字。由于scala中xml節(jié)點(diǎn)和節(jié)點(diǎn)序列是不可變的伪煤,若要修改一個(gè)節(jié)點(diǎn),需創(chuàng)建拷貝凛辣,給出修改抱既,在拷貝未修改的部分。RuleTransformer類(lèi)的transform方法遍歷給定節(jié)點(diǎn)的所有后代扁誓,應(yīng)用所有規(guī)則防泵,最后返回經(jīng)過(guò)變換的樹(shù)。
Scala中的ContructingParser是個(gè)解析器蝗敢,用于加載xml捷泞,可以保留注釋?zhuān)珻DATA和空白,用doc.dtd可以訪(fǎng)問(wèn)到DTD寿谴。
保存XML時(shí)锁右,沒(méi)有內(nèi)容的元素不會(huì)被寫(xiě)成自結(jié)束的標(biāo)簽。Scala中每個(gè)元素都有一個(gè)scope屬性讶泰,類(lèi)型為NamespaceBinding,該類(lèi)的Uri屬性輸出命名空間的URI咏瑟。
高級(jí)函數(shù)和高級(jí)類(lèi)型
在scala中,函數(shù)是頭等公民痪署,可以用變量存儲(chǔ)函數(shù)码泞,可以使用匿名函數(shù),和帶參數(shù)的函數(shù)狼犯。如果需要一個(gè)序列的值余寥,一般從一個(gè)簡(jiǎn)單序列轉(zhuǎn)化得出。函數(shù)可以在變量不再作用域內(nèi)時(shí)被調(diào)用悯森,這樣的函數(shù)叫閉包宋舷。
柯里化是指將原來(lái)接受兩個(gè)參數(shù)變成接受一個(gè)參數(shù)的函數(shù)的過(guò)程。不需要用return語(yǔ)句來(lái)返回函數(shù)值呐馆,函數(shù)的返回值就是函數(shù)體的值肥缔。
scala中,用方括號(hào)來(lái)定義類(lèi)型參數(shù)汹来,從調(diào)用該方法的實(shí)際參數(shù)來(lái)推斷出類(lèi)型续膳。視圖界定 T<%V要求必須存在一個(gè)從T到V的隱式轉(zhuǎn)換,Manifest對(duì)象是構(gòu)造器的隱式參數(shù)收班,可用于上下文界定坟岔,類(lèi)型變化的方向和子類(lèi)型方向是相反的。
函數(shù)在參數(shù)上是逆變的摔桦,在返回值上的協(xié)變的社付,對(duì)象是不能泛型化的承疲。
在內(nèi)部,編譯器將所有嵌套的類(lèi)型表達(dá)式a.b.c.T都翻譯成類(lèi)型投影a.b.c.type#T鸥咖。對(duì)應(yīng)復(fù)雜類(lèi)型燕鸽,可用type關(guān)鍵字創(chuàng)建一個(gè)簡(jiǎn)單的別名,type同樣被用于那些在子類(lèi)中被具體化的抽象類(lèi)型。
結(jié)構(gòu)類(lèi)型指的是一組關(guān)于抽象方法啼辣,字段和類(lèi)型的規(guī)格說(shuō)明啊研,可用安全而方便的反射調(diào)用。
在scala中鸥拧,通過(guò)特質(zhì)和自身類(lèi)型達(dá)到一個(gè)簡(jiǎn)單的依賴(lài)注入效果党远。如果類(lèi)型是在類(lèi)實(shí)例化時(shí)給出,則使用泛型富弦,如果類(lèi)型是在子類(lèi)中給出沟娱,則使用抽象類(lèi)型。
List這樣的泛型類(lèi)型有時(shí)稱(chēng)為類(lèi)型構(gòu)造器腕柜。Container特質(zhì)是scala集合類(lèi)庫(kù)中使用的構(gòu)建器機(jī)制的的簡(jiǎn)化版济似。
Actor
actor提供了并發(fā)程序中與傳統(tǒng)的基于鎖的結(jié)構(gòu)不同的另一種選擇,通過(guò)盡可能避免鎖和共享狀態(tài)盏缤,actor更容易地設(shè)計(jì)出正確碱屁、沒(méi)有死鎖或爭(zhēng)用狀況的程序。Scala提供了actor的簡(jiǎn)單實(shí)現(xiàn)蛾找,akka(http://akka.io)提供了高級(jí)actor類(lèi)庫(kù)娩脾。
每個(gè)actor都要擴(kuò)展Actor類(lèi)并重寫(xiě)Act方法,actor是處理異步消息的對(duì)象打毛,消息可以是任何對(duì)象柿赊,通過(guò)!操作符發(fā)送消息幻枉,例如:
actorX 碰声!“happy new year”
一個(gè)好的方式是使用樣例類(lèi)作為消息,這樣熬甫,actor可以使用模式匹配了胰挑。發(fā)送的消息存放在mailbox,receive方法從mailbox中取下一條消息并處理椿肩,如果在receive方法被調(diào)用時(shí)并沒(méi)消息瞻颂,則該調(diào)用會(huì)阻塞,直到有消息抵達(dá)郑象。actor可以安全地修改它自己的數(shù)據(jù)贡这。
向其他actor發(fā)送消息的方法:
- 使用全局的actor
- actor可以構(gòu)造成帶有指向一個(gè)或更多actor的引用
- actor可接收帶有指向另一個(gè)actor的引用的消息
- actor可以返回消息給發(fā)送方
actor可以發(fā)送一個(gè)消息并等待回復(fù),用3ч弧盖矫?操作符即可丽惭,盡量避免同步消息。
actor的act方法在actor的start方法被調(diào)用時(shí)開(kāi)始執(zhí)行辈双。接下來(lái)進(jìn)入某個(gè)循環(huán)责掏,終止條件如下:
- act方法返回
- act方法由于異常被終止
- actor調(diào)用exit方法
通過(guò)link方法可以將不同的actor鏈接在一起。
actor的設(shè)計(jì)原則如下:
- 避免使用共享狀態(tài)
- 不要調(diào)用actor的方法
- 保持每個(gè)actor簡(jiǎn)單
- 上下文數(shù)據(jù)包含在消息中
- 最小化給發(fā)送方回復(fù)
- 最少阻塞調(diào)用
- 使用react
- 建立失敗區(qū)