程式扎記: [Scala 小學堂] Scala Gossic : 了解更多 - 定義類別 (apply() 與 update() 方法)

標籤

2016年6月20日 星期一

[Scala 小學堂] Scala Gossic : 了解更多 - 定義類別 (apply() 與 update() 方法)

轉載自 這裡
前言 :
Scala 是一個可直譯、編譯、靜態、運行於 JVM 之上、可與 Java 互操作、融合物件導向編程特性與函式編程風格的程式語言. Scala 本身具有擴充性,不過這必須了解更多語法特性與細節. Scala 建構式有些限制,使用方法可以定義所謂運算子(Operator),提供語法蜜糖與存取方法.

apply() 與 update() 方法 :
在介紹 Array 時曾經談過,如果要存取陣列,必須指定陣列索引,與其它語言存取陣列慣例不同的是,在 Scala 中,指定陣列索引時是使用 () 而非 [],例如 :
- UpdateApply1.scala 代碼 :
  1. val arr = new Array[Int](3)  
  2. arr(0) = 10  
  3. arr(1) = 20  
  4. arr(2) = 30  
  5. println(arr(0))  
  6. println(arr(1))  
  7. println(arr(2))  

事實上,上面的程式,Scala會分別將之轉換為 update() 與 apply() 方法的呼叫 :
- UpdateApply2.scala 代碼 :
  1. val arr = new Array[Int](3)  
  2. arr.update(010)  
  3. arr.update(120)  
  4. arr.update(230)  
  5. println(arr.apply(0)) // 顯示 10  
  6. println(arr.apply(1)) // 顯示 20  
  7. println(arr.apply(2)) // 顯示 30  

參考名稱後直接使用 () 的寫法,其實是 Scala 所提供的語法蜜糖只要遇到 (),Scala就會試著將之展開為 apply() 呼叫,例如 some 若是參考名稱,則呼叫 some(.....),則 Scala 就會試著展開並呼叫 some.apply(...),而只要遇到 ()= 呼叫,則 Scala 就會試著展開 為update()=呼叫,例如寫下 some(...) = value,則 Scala 會試著展開並呼叫 some.update(...) = value . 所以任何類別只要有提供 apply() 方法或 update(),就可以使用 () 或 ()= 寫法,例如 :
- UpdateApply3.scala 代碼 :
  1. class Some {  
  2.     def apply(a: Int) = a + " from apply...."  
  3.     def update(a: Int, b: Int) = a + ", " + b + " from update..."  
  4. }  
  5.   
  6. val some = new Some()  
  7. println(some(1))         // 1 from apply....  
  8. println(some(2) = 10)    // 2, 10 from update...  

基本上,參數也不只能有一個,而參數可以是任何的型態(畢竟只是語法蜜糖),例如 :
- UpdateApply4.scala 代碼 :
  1. class Some {  
  2.     def apply(a: String) = a + " from apply...."  
  3.     def apply(a: String, b: String) = a + ", " + b + " from apply..."  
  4.     def update(a: String, b: String) = a + ", " + b + " from update..."  
  5.     def update(a: String, b: String, c: String) =  
  6.             a + ", " + b + ", " + c + " from update..."  
  7. }  
  8.   
  9. val some = new Some()  
  10. println(some("data1"))                    // data1 from apply....  
  11. println(some("data1""data2"))           // data1, data2 from update...  
  12. println(some("data3") = "data4")          // data3, data4 from update...  
  13. println(some("data3""data4") = "data5"// data3, data4, data5 from update...  

也可以使用 重複參數,只要記得,如果是()=,等號右邊就是update()最後一個參數 :
- UpdateApply5.scala 代碼 :
  1. class Some {  
  2.     def apply(args: String*) = args.mkString(",")  
  3.     def update(args: String*) = args.mkString(",")  
  4. }  
  5.   
  6. val some = new Some()  
  7. println(some("data1"))                       // data1  
  8. println(some("data1""data2"))              // data1,data2  
  9. println(some("data3") = "data4")             // data3,data4  
  10. println(some("data3""data4") = "data5")    // data3,data4,data5  

同樣的原則也可以套用在 單例物件 上,先前在單例物件也有提過,可以在定義單例物件時提供一個apply方法 :
- UpdateApply6.scala 代碼 :
  1. class Resource private {  
  2.     def service(request: String) = request + "...processed..."  
  3. }  
  4.   
  5. object Resource {  
  6.     private val resource = new Resource  
  7.     def apply() = resource  
  8. }  
  9. val resource = Resource()  
  10. println(resource.service("XD"))  

那麼你就可以這麼使用 :
  1. val resource = Resource()  
  2. println(resource.service("XD"))  
Scala 會自動將 Resource() 的呼叫,轉換為 Resource.apply() 的呼叫。技術上,object Resource 的語法,Scala 會產生一個 Resource$ 類別,你在 Resource 中定義的方法,會是Resource$ 類別中的方法之一,而程式中 Resource 是個參考名稱,參考至 Resource$ 的實例。依這個邏輯來看,你可以直接使用 Resource() 這樣的語法就是很自然的結果,而且就可以知道,如果願意,你也可以定義 update() 方法,例如 :
- UpdateApply7.scala 代碼 :
  1. object Some {  
  2.     def apply(args: String*) = args.mkString(",")  
  3.     def update(args: String*) = args.mkString(",")  
  4. }  
  5.   
  6. println(Some("data1"))                       // data1  
  7. println(Some("data1""data2"))              // data1,data2  
  8. println(Some("data3") = "data4")             // data3,data4  
  9. println(Some("data3""data4") = "data5")    // data3,data4,data5  


沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!