建構式


Scala 在定義類別時,類別本體部份是主要建構式的範圍,稱之為主要建構式 (Primary constructor)。例如:
class Account {
    // 這個區塊中整個都是主要建構式
    ...
}

如果在建立類別時,需要給定初始值,則可以在類別名稱之後接上括號定義參數列:
class Account(d: String, n: String) {
    val id = d
    val name = n
    ...
}

在上例中,d與n在整個主要建構式區塊中是可見的,整個 區塊範圍中都可以直接取得d與n的值,d與n預設是private val,所以不可以改變d與n的值,建構物件後也無法透過物件直接存取d與n。

如果你明確使用val或var來宣告參數,則預設就是公開的,例如:
class Account(val id: String, val name: String) {
    ...
}

所以你可以直接在建構物件後,透過物件存取id與name,例如:
class Account(val id: String, val name: String) {
private var bal: Int = _

def deposit(amount: Int) {
require(amount > 0) // 不能存負數
bal += amount
}

def withdraw(amount: Int) {
require(amount > 0) // 不能提負數
if(amount <= bal) {
bal -= amount
}
else {
throw new RuntimeException("餘額不足")
}
}

def balance = bal
}

val acct = new Account("123-456-789", "Justin Lin")
println(acct.id) // 顯示 123-456-789
println(acct.name) // 顯示 Justin Lin

如果你需要定義別的建構式,則可以在類別中定義this(..)方法,例如:
class Account(val id: String, val name: String) {
private var bal: Int = _

def this(id: String, name : String, bal: Int) = {
this(id, name)
this.bal = bal
}

def deposit(amount: Int) {
require(amount > 0) // 不能存負數
bal += amount
}

def withdraw(amount: Int) {
require(amount > 0) // 不能提負數
if(amount <= bal) {
bal -= amount
}
else {
throw new RuntimeException("餘額不足")
}
}

def balance = bal
}

val acct = new Account("123-456-789", "Justin Lin", 100)
println(acct.id) // 顯示 123-456-789
println(acct.name) // 顯示 Justin Lin
println(acct.balance) // 顯示 100

相對於主要建構式,你使用this定義的建構式(方法或函式)稱之為輔 助建構式(Auxiliary constructor),在輔助建構式中第一個動作,一定得呼叫其它的輔助建構式或是主 要建構式,這是透過this(...)來呼叫所以,所以最後一定會(要)有個輔助建構式得呼叫主要建構式。

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

輔 助建構式在定義時就如同在定義方法,輔助建構式的參數id、name與bal是val,作用範圍僅在this(...)方法之中(不像主要建 構式,其參數 作用範圍是整個類別),如果你要讓傳入的值整個類別可用,得像上例中指定給類別成員,其中this.bal的this表示物件本身(this 的作用與其它 語言相同,例如Java)。

雖然還沒談到類別的繼承,不過你可以先知道的是,由於在Scala中,輔助建構式第一行只能是this(...)來呼叫其它輔助建構式或主要 建構式,所以,輔助建構式是不能呼叫父類別建構式的,在Scala中, 只有主要建構式可以呼叫父類別建構式(可以是父類別的輔助建構式或主要建構式)