Scala 是構建在 JVM 上的靜態類型的腳本語言,而腳本語言總是會有些約定來增強靈活性。靈活性可以讓掌握了它的人如魚得水,也會讓初學者不知所措。比如說 Scala 爲配合 DSL 在方法調用時有這麼一條約定:
在明確了方法調用的接收者的情況下,若方法只有一個參數時,調用的時候就可以省略點及括號。如 “0 to 2”,實際完整調用是 “0.to(2)”。但 “println(2)” 不能寫成 “println 10“”,因爲未寫出方法調用的接收者 Console,所以可以寫成 “Console println 10”
到這裏就要講到 apply 和 update 方法相關的約定,描述的是直接在變量(對象)後直接加圓括號的代碼的情況下,那就是:
用括號傳遞給變量(對象)一個或多個參數時,Scala 會把它轉換成對 apply 方法的調用;與此相似的,當對帶有括號幷包括一到若干參數的進行賦值時,編譯器將使用對象的 update 方法對“括號裏的參數和等號右邊的值”執行調用。
對上面那段話的解釋可由下面幾個例子得到很好的理解
1. theArray(0), 取數組的第一個元素的操作會轉換成 theArray.apply(0) 操作,這也能解釋爲什麼 Scala 數組取值不用中括號括下標的方式,因爲它也是一次方法調用
2. anyObject("key1") 會被轉換成 anyObject.apply("key") 操作,這也會讓我們想到 Map 的取值操作,的確如此。我們可以作個例子:
- classSomeClass {
- defapply(key:String):String ={
- println("apply method called, key is: " + key)
- "Hello World!"
- }
- }
- valanyObject =new SomeClass
- println(anyObject("key1"))
執行後輸出結果是:
apply method called, key is: key1
Hello World!
說明是調用到了相應的 apply 方法的。
3. 我們在構造 Array 或 Map 時,會簡單的寫成
- valnumNames =Array("zero","one","two")
這裏也是調用的 apply 方法,我們看起來好像是作用在類 Array 上的,其實不然,而是作用在 Array 的伴生對象(object Array)上的,調用的是伴生對象 Array 的 apply 方法,即:
- valnumNames =Array.apply("zero","one","two")
上面的功效像是調用的 Array 類的 apply 工廠方法。同樣看個單例對象的例子,也解釋了伴生對象的 apply 方法的調用
- objectEMail {
- defapply(user:String, domain:String):String ={
- println("apply method called")
- user + "@"+ domain
- }
- }
- valemail =EMail("lyrebing","hotmail.com")
- println(email)
上面代碼執行後輸出結果是:
apply method called
[email protected]
有了前面 apply 方法的理解,下面對 update 方法的理解就很順暢了,比如:
- greetStrings(0)="Hello"
會轉換成調用
- greetStrings.update(0,"Hello")
來個複雜的 Demo,賦值時等號左邊帶兩個參數,並且賦值操作會產生返回值的情況(純粹用於演示)
- classSomeClass {
- defupdate(arg1:Int, arg2:String, arg3:String):String ={
- println("update method called")
- arg1+ "|"+ arg2+ "|"+ arg3
- }
- }
- valobj =new SomeClass
- valresult =(obj(1,"key1")="Hello")
- println(result)
執行後輸出結果爲:
update method called
1|key1|Hello
在應用 apply 和 update 規則時,關鍵是轉換後的調用要找到相應的方法原型。再就是應用 update 時,等號右邊的值會作爲 update 方法的最後一個參數。