programming in Scala 學習(二)

(9-21章)


1. java通過private可以使類內部方法私有化,對外不可見。Scala除了private方式,還可以使用本地函數(內嵌在函數中的函數)實現,本地函數僅在包含它的函數代碼塊中可見,外部無法訪問。在作用域方面,本地函數可以訪問包含它的外層函數的入參,不需要再傳入參數。


2. 函數是Scala的頭等函數(first-class function)或頭等結構,不僅可以像java那樣定義和調用函數,還可以把函數寫成匿名的函數字面量(function literal),例如(x: Int) => x+1,並把它們作爲值(value)傳遞,可以用於賦值方式定義函數,或作爲函數調用參數傳遞入參,或者只給出類型作爲函數聲明定義的入參,等等場合。函數字面量被編譯到類,在運行期實例化爲函數值,函數字面量與函數值的區別在於,函數字面量存在與源代碼,函數值存在於運行期,這個區別很像類(源代碼)和對象(運行期)之間的關係。用函數字面量是通過賦值定義一個函數,與def 關鍵字聲明定義一個函數,兩者寫法規則的不同點需要區分留意。


3. 函數值是對象,如果願意,可以將其存入變量,存入後的變量也是函數,變量名即函數名,可以用通常的  括號()  或  括號(參數)  編寫此函數調用。


4. 函數字面量可以包含多條語句,用花括號包住函數體,當函數值被調用時,所有的語句將被執行,函數返回值是最後一行表達式產生的值。


5. 函數字面量更簡短的表達方式:1)去除參數類型;2)去除無用字符,如多餘的括號;3)使用下劃線當作一個參數的佔位符,函數字面量中可以使用多個下劃線代表多個參數的佔位,前提是每個參數在函數字面量中出現且僅出現一次,第一個佔位符代表第一個參數,第二個佔位符代表第二個參數,依此類推,有時使用佔位符編譯器可能無法推斷出缺失的參數類型,可以在佔位符後面寫上冒號和指定缺失的參數類型,用括號括起來,明確告訴編譯器參數類型。


6. 部分應用函數(partially applied function)可以使用一個下劃線替換整個參數列表,如println(_)或println _,後者函數名和下劃線之間,一定要有一個空格,否則編譯器會認爲是在說明一個不同帶符號的名字。


7. Scala的重複可變參數---在參數類型之後放一個星號,例如,def echo( args : String*) = for( arg <- args ) println(arg),args的類型實際是數組Array[String],如果已有一個Array[String]數組,比如val arr = Array("a", "b", "c"),傳入echo函數作爲參數,不能寫成echo(arr),需要寫成echo(arr: _*),表示arr的每個元素當作參數傳入,而不是單一的一個arr數組參數。


8. 如果程序符合Scala尾遞歸情況,編譯器將檢測並把到尾遞歸替換成一個回到遞歸函數開頭的跳轉,尾遞歸不會爲每次遞歸調用產生新的堆棧結構,追蹤堆棧打印信息可以看到,尾遞歸只對遞歸函數做一次函數壓棧,每次尾遞歸調用都會跳轉到這一次壓棧的一個棧內完成。Scala尾遞歸使用侷限較大,還是可以用while替代。


9. 函數字面量定義形式,可以帶有在函數作用域之外定義的自由變量,這樣的函數字面量在運行期創建的函數值(對象)被稱爲閉包(closure)。閉包對捕獲的自由變量修改值的改變在閉包之外也可見。如果閉包使用了某個函數的本地變量,每次函數調用時會創建一個新閉包,每個閉包會訪問閉包創建時活躍的變量值。閉包的函數值(對象)被編譯器創建在堆中,不是棧裏。


10. 高階函數(high-order function),可以調用傳入的函數值(不是函數名)做參數,配合參數的佔位符與Scala支持的函數閉包功能,組織和簡化代碼。


11. Scala的類方法,如果沒有實現(沒有等號或方法體),它就是抽象的,具有抽象成員的類本身必須被聲明爲抽象的,在class關鍵字之前加上abstract修飾符,說明類有抽象的未實現的成員,抽象類不能被實例化。


12. Scala裏禁止在同一個類中使用同樣的名稱定義字段和方法,java允許,原因是java爲定義準備了4個命名空間(字段、方法、類型和包),Scala只有2個命名空間:值(字段、方法、包、單利對象)和類型(類和特質名)。


13. Scala的類和構造器可以交織在一起,體現爲類名後面可以加參數,相當於傳給默認主構造器的函數參數。一個類有一個主構造器和任意數量的輔助構造器,而每個輔助構造器都必須以對先前定義的輔助構造器或主構造器的調用開始。這樣做帶來的後果是,輔助構造器永遠都不可能直接調用超類的構造器。子類的輔助構造器最終都會調用主構造器,只有主構造器可以調用超類的構造器。


14. Scala特質的兩種常用方式:拓寬瘦接口爲胖接口;定義可堆疊的改變(stackable modification)。通過extends關鍵字混入特質,隱式繼承特質的超類,或者extends顯示指明待擴展的超類,用with混入特質。


15. 特質像是具有具體方法的java接口,但又有不同,特質定義不能有任何“類”參數,而且特質處理super調用是運行時動態綁定。特質定義如果extends了其他超類,特質中重寫的方法調用了super,前面都需要寫上abstract override關鍵字。


16. Scala把類定義中,該類和繼承的超類以及特質,以線性化的次序放在一起,首先是該類,然後根據類聲明定義,從右向左按次序線性化超類和特質,依次實現可堆疊的調用行爲,比如按上述線性化順序依次對super調用。(page 147)


17. 定義了 case class + 類名,表示Scala的樣本類(case class),編譯器會自動爲樣本類添加與類名一致的工廠方法、toString、hashCode、equals等方法,樣本類方便在模式匹配match---case編碼中使用構造器模式,進行深度匹配。(page 176)


18. Scala的類型參數可以用於編寫泛型和特質。默認情況下,Scala的泛型類型是非協變的子類型化(即泛型沒有繼承關係,跟java一樣),但可以通過+號,比如+T,告訴編譯器該泛型是協變的,支持繼承關係,或者-T實現繼承關係的逆變。(page 254)


19. new + 特質名+{類結構體},這個表達式產生混入了特質並被結構體定義的匿名類實例。


20. 用implicit標記的變量、方法、對象定義等,是Scala的隱式操作,編譯時編譯器將考慮隱式轉換。結合泛型使用時,<% 表示隱式參數的視界,與上界<意義不一樣,上界表示"子類"關係,視界表示隱式參數的"可當作..."關係,不要求是子類。(page 298)





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章