在Scala中,如果方法只接受一個引數,則可以省略. 與括號。例如:
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 && amount < bal) // 不能提負數,不能超過餘額
bal -= amount
}
def balance = bal
}
val acct = new Account("123-456-789", "Justin")
acct deposit 100 // 等於 acct.deposit(100)
acct withdraw 50 // 等於 acct.withdraw(50)
println(acct.balance) // 顯示 50
這讓方法在操作時像是個內建的運算子。例如,你可以定義一個複數類別如下操作:
class Complex(val re: Double, val im: Double) {
def add (that: Complex) = new Complex(re + that.re, im + that.im)
def minus (that: Complex) = new Complex(re - that.re, im - that.im)
override def toString =
re + (if (im < 0) " - " + (-im) else " + " + im) + " i"
}
val c1 = new Complex(4, 2)
val c2 = new Complex(2, 1)
println(c1 add c2) // 顯示 6.0 + 3.0 i
println(c1 minus c2) // 顯示 2.0 + 1.0 i
上 例中,toString是由scala.AnyRef繼承下來,你將整重新定義(Override)傳回字串描述,像println函式會直接使用 toString的傳回值來顯示,在Scala中,要重新定義父類別中的某個方法,一定得使用override關鍵字,這之後還會詳談。
事實上,在Scala中,像+、-、*、/這類的「運算子」,其實都是方法名稱(Scala實際上來說並沒有運算子)。你可以直接如下定義複數類別與簡單的運算:
class Complex(val re: Double, val im: Double) {
def + (that: Complex) = new Complex(re + that.re, im + that.im)
def - (that: Complex) = new Complex(re - that.re, im - that.im)
def * (that: Complex) = new Complex(re * that.re - im * that.im,
re * that.im + im * that.re)
def / (that: Complex) = {
val d = that.re * that.re + that.im * that.im
new Complex((re * that.re + im * that.im) / d,
(im * that.re - re * that.im) / d)
}
override def toString =
re + (if (im < 0) " - " + (-im) else " + " + im) + " i"
}
val c1 = new Complex(4, 2)
val c2 = new Complex(2, 1)
println(c1 + c2) // 顯示 6.0 + 3.0 i
println(c1 - c2) // 顯示 2.0 + 1.0 i
println(c1 * c2) // 顯示 6.0 + 8.0 i
println(c1 / c2) // 顯示 2.0 + 0.0 i
在傳統語言中的運算子,在Scala中可以定義為方法的有:
- 算術操作:如+、-、*、/、%
- 關係操作:如>、>=、<、<=
- 邏輯操作:如&&、||、!
- 位元操作:如&、|、~、^、>>、>>>、<<
- 指定操作:如+=、-=、*=、/=、%=、&=、|=、~=、>>=、>>>=、<<=
注意!你不可以定義==與!=,因為==與!=定義在 scala.Any 中,且被宣告為 final,你也不可以重新定義eq與ne,因為它們定義在 scala.AnyRef 中,也是被宣告為final,如果你要定義物件內容值是否相同,則要重新定義 equals()方法(與Java相同),因為Any中定義的==或!=方法,會呼叫equals()來檢查物件的相等性。
對於一些運算如補數~這樣的操作,是擺在某個數值或物件之前的運算,Scala使用「unary_」作為這種前置運算的方法名稱前置,例如若要定義~這樣的運算,則在定義類別時定義「unary_~」這樣的方法名稱,當你呼叫~2,實際上等於呼叫(2).unary_~:
scala> ~2
res15: Int = -3
scala> (2).unary_~
res16: Int = -3
scala>
res15: Int = -3
scala> (2).unary_~
res16: Int = -3
scala>
不過,Scala限制可以作為前置運算的符號,只有+、-、!與~可以作為前置運算,如果你定義其它的符號,例如定義了unary_#,你仍然可以使用x.unary_#的方式呼叫(x參考至物件),但#x這樣的前置運算則是不行的(Scala的將之解釋為#.x)。