2016年6月14日 星期二

[Scala 小學堂] Scala Gossic : 了解更多 - 定義類別 (建構式)

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

建構式 : 
Scala 在定義類別時,類別本體部份是主要建構式的範圍,稱之為主要建構式Primary constructor)。例如 : 
  1. class Account {  
  2.     // 這個區塊中整個都是主要建構式  
  3.     ...  
  4. }  
如果在建立類別時,需要給定初始值,則可以在類別名稱之後接上括號定義參數列 : 
  1. class Account(d: String, n: String) {  
  2.     val id = d  
  3.     val name = n  
  4.     ...  
  5. }  
在上例中,d 與 n 在整個主要建構式區塊中是可見的,整個區塊範圍中都可以直接取得 d 與 n 的值,d 與 n 預設是 private val,所以不可以改變 d 與 n 的值,建構物件後也無法透過物件直接存取 d 與 n. 如果你明確使用 val 或 var 來宣告參數,則預設就是公開的,例如 :
  1. class Account(val id: String, val name: String) {  
  2.     ...  
  3. }  
所以你可以直接在建構物件後,透過物件存取 id 與 name,例如 : 
- Constructor1.scala :
  1. class Account(val id: String, val name: String) {  
  2.         private var bal: Int = 0  
  3.   
  4.         def deposit(amount: Int) {  
  5.                 require(amount >0)  
  6.                 bal += amount  
  7.         }  
  8.   
  9.         def withdraw(amount: Int) {  
  10.                 require(amount > 0)  
  11.                 if(amount <= bal) {  
  12.                         bal -= amount  
  13.                 } else {  
  14.                         throw new RuntimeException("Not enough");  
  15.                 }  
  16.         }  
  17.   
  18.         def balance = bal  
  19. }  
  20.   
  21. val acct = new Account("123-456-789""John Lee")  
  22. println(acct.id)  
  23. println(acct.name)  

如果你需要定義別的建構式,則可以在類別中定義 this(..)方法,例如 : 
- Constructor2.scala 代碼 :
  1. class Account(val id: String, val name: String) {  
  2.     private var bal: Int = _  
  3.   
  4.     def this(id: String, name : String, bal: Int) = {  
  5.         this(id, name)  
  6.         this.bal = bal  
  7.     }  
  8.   
  9.     def deposit(amount: Int) {  
  10.         require(amount > 0// 不能存負數  
  11.         bal += amount  
  12.     }  
  13.   
  14.     def withdraw(amount: Int) {  
  15.         require(amount > 0)     // 不能提負數  
  16.         if(amount >= bal) {  
  17.             bal -= amount  
  18.         }  
  19.         else {  
  20.             throw new RuntimeException("餘額不足")  
  21.         }  
  22.     }  
  23.   
  24.     def balance = bal  
  25. }  
  26.   
  27. val acct = new Account("123-456-789""Justin Lin"100)  
  28. println(acct.id)        // 顯示 123-456-789  
  29. println(acct.name)      // 顯示 Justin Lin  
  30. println(acct.balance)   // 顯示 100  

相對於主要建構式,你使用 this 定義的建構式(方法或函式)稱之為 輔助建構式Auxiliary constructor),在輔助建構式中第一個動作,一定得呼叫其它的輔助建構式或是主要建構式,這是透過 this(...) 來呼叫所以,所以最後一定會()有個輔助建構式得呼叫主要建構式. 從以上這個限制來看,輔助建構式執行建構物件所必要的基本流程,為建構物件的單一入口。以上例來看,建構帳戶時一定必需的,就是帳戶(id)、名稱(name)及餘額(bal),所以規範在主要建構式中,而無論如何,你一定得提供帳戶與名稱,而餘額可以有預設值 0,所以主要建構式的參數列必須有 id 與 name。為了建構方便,提供一個輔助建構式可以設定初始餘額,由於最後一定會有個輔助建構式呼叫主要建構式,所以 id 與 name 絕不會是預設值. 

輔助建構式在定義時就如同在定義方法,輔助建構式的參數 idname 與 bal 是val,作用範圍僅在 this(...) 方法之中不像主要建構式,其參數 作用範圍是整個類別),如果你要讓傳入的值整個類別可用,得像上例中指定給類別成員,其中 this.bal 的 this 表示物件本身(this 的作用與其它 語言相同,例如Java). 雖然還沒談到類別的繼承,不過你可以先知道的是,由於在 Scala 中,輔助建構式第一行只能是 this(...) 來呼叫其它輔助建構式或主要建構式,所以,輔助建構式是不能呼叫父類別建構式的,在 Scala 中,只有主要建構式可以呼叫父類別建構式可以是父類別的輔助建構式或主要建構式). 

Supplement 
Tutorialspoint - Scala Classes & Objects

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...