在 Scala中要定義類別非常的簡單,例如你可以定義一個帳戶(Account)類別:
class Account
val acct = new Account
上例中,class用來定義一個類別,在上例中,Account是個公開(Public)類別,在Scala中定義類別時,沒有指定存取權限 的話,預設就是公開類別。
new 則根據類別定義來建立實例(Instance),由於建立物件時不需給定引數作為建構之用,所以括號可以省略。在Scala中,你可以在同一 個.scala檔案中定義多個類別,這方便你在開發時撰寫一些簡單的指令稿 (Script),不過建議為每個類別撰寫一個.scala,主檔名為類別名稱相同,如此別的開發人員要檢視你的相關類別時,可以很快地找到 相對應的原始 碼。
上面這個例子不並不能作什麼,一個帳戶基本上要有帳號、名稱、餘額,也要有存款、提款的功能,來看看下面這個例子:
class Account(acctNumber: String, acctName: String) {
val id = acctNumber
val name = acctName
private var bal = 0
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
}
這個類別已包含幾個Scala中定義類別的觀念。首先是:
class Account(acctNumber: String,
acctName: String)
這定義了一個類別,接受兩個引數作為建構之用,所以你可以用以下方式來建構物件:
val acct = new
Account("123-456-789", "Justin Lin")
雖然語法上沒有指出,不過acctNumber與acctName都是private val宣告的,所以在類別中不能改變它的值,acctNumber與acctName實際上會成為類別中的private 成員,所以無法直接透過物件實例存取acctNumber與acctName(更精確地說,其實是 private[this] val,也就是所謂物件私有(object-private)權限修飾,在Account類別中也無法透過另一Account實例來存取其acctNumber 與acctName,之後還會詳談)。如果你熟悉Java,上面這個程式片 段,相當於Java的:
// 這是 Java
public class Account {
private final String acctNumber;
private final String acctName;
public Account(String acctNumber, String acctName) {
this.acctNumber = acctNumber;
this.acctName = acctName;
}
}
public class Account {
private final String acctNumber;
private final String acctName;
public Account(String acctNumber, String acctName) {
this.acctNumber = acctNumber;
this.acctName = acctName;
}
}
再來繼續看:
class Account(acctNumber: String,
acctName: String) {
val id = acctNumber
val name = acctName
private var bal = 0
}
val id = acctNumber
val name = acctName
private var bal = 0
}
類別上的參數與本體定義了一個主要建構式(Primary constructor),id與name沒有使用任何存取修飾,預設為公開(Public),bal則使用 private宣告為私用。上面的片段若要以Java來類比,相當於以下的Java程式:
// 這是 Java
public class Account {
private final String acctNumber;
private final String acctName;
public final String id;
public final String name;
private int bal;
public Account(String acctNumber, String acctName) {
this.acctNumber = acctNumber;
this.acctName = acctName;
this.id = acctNumber;
this.name = acctName;
}
}
public class Account {
private final String acctNumber;
private final String acctName;
public final String id;
public final String name;
private int bal;
public Account(String acctNumber, String acctName) {
this.acctNumber = acctNumber;
this.acctName = acctName;
this.id = acctNumber;
this.name = acctName;
}
}
接下來在類別本體中,還定義了一些函式,在類別中的函式,物件導向上通常稱之為方法(Method),由於定義方法時沒有任何存取修飾,所以 預設就是公開(Public),剩下的觀念,在 簡 單的函式 中都有提到。同樣地,在類別中使用val宣告了資料成員(Field),沒有 指定任何存取修飾的話,預設就是公開。
require函式給依你給定的條件進行判斷,如果運算是true則什麼事都不會發生,如果運算是false,則丟出 java.lang.IllegalArgumentException。
每個建構出來的Account實例,都會擁有自己的資料狀態,以下是個建構與使用物件的範例:
val acct = new Account("123-456-789", "Justin Lin")
acct.deposit(1000)
acct.withdraw(400)
println(acct.name)
println(acct.balance)
在Scala中,如果函式或方法不帶參數,則括號可以省略。實際上,上面的Account類別在定義上還可以再簡化一些,先前說 過,雖然沒有表明,不過acctNumber與acctName都是private val宣告的,所以在類別中不能改變它的值,但如果你直接在上頭宣告val的話,若沒有指定存取修飾,則預設就是公開。例如:
class Some(val name: String) { //
name 預設是公開
...
}
...
}
其實像是你這麼宣告:
class Some(x: String) {
val name = x
}
val name = x
}
所以,上面的Account也可以定義為:
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
}
在bal的撰寫上,預設值寫為_,這代表著依型態自動給出預設值,如果是整數則設定為0,如果是浮點數則設定為0.0,如果是布林值則設定為 false,如果是其它物件型態則設定為null。