Scala學習(二)——高級特性
apply() 方法
apply方法是Scala提供的一個語法糖
類名+括號,調用對象的apply方法
對象名+括號,調用類的apply方法
對apply方法的簡單測試:(其中,帶 new -- class ApplyTest,不帶 new -- object ApplyTest)
class ApplyTest {
println("class ApplyTest")
def apply() {
println("class APPLY method")
}
}
object ApplyTest {
println("object ApplyTest")
def apply() = {
println("object APPLY method")
new ApplyTest()
}
}
// 對象名+括號,調用類的apply方法
val a1 = new ApplyTest()
a1() // == a1.apply()
// 輸出 class ApplyTest, class APPLY method
// 類名+括號,調用對象的apply方法
val a2 = ApplyTest()
// 輸出 object ApplyTest, object APPLY method, class ApplyTest
val a2 = ApplyTest()
a2()
// 輸出 object ApplyTest, object APPLY method, class ApplyTest, class APPLY method
val a3 = ApplyTest
// 輸出 object ApplyTest
val a3 = ApplyTest
a3()
// 輸出 object ApplyTest, object APPLY method, class ApplyTest
單例對象
單例對象用於持有一個類的唯一實例。通常用於工廠模式。
object Timer {
var count = 0
def currentCount(): Long = {
count += 1
count
}
}
可以這樣使用:
Timer.currentCount() //1
單例對象可以和類具有相同的名稱,此時該對象也被稱為“伴生對象”。我們通常將伴生對象作為工廠使用。
下面是一個簡單的例子,可以不需要使用’new’來創建一個實例了。
class Bar(foo: String)
object Bar {
def apply(foo: String) = new Bar(foo)
}
函數即對象
在Scala中,我們經常談論對象的函數式編程。這是什麽意思?到底什麽是函數呢?
函數是一些特質的集合。具體來說,具有一個參數的函數是Function1特質的一個實例。這個特質定義了apply()語法糖,讓你調用一個對象時就像你在調用一個函數。
object addOne extends Function1[Int, Int] {
def apply(m: Int): Int = m + 1
}
addOne(1) // 2
這個Function特質集合下標從0開始一直到22。為什麽是22?這是一個主觀的魔幻數字(magic number)。我從來沒有使用過多於22個參數的函數,所以這個數字似乎是合理的。
apply語法糖有助於統一對象和函數式編程的二重性。你可以傳遞類,並把它們當做函數使用,而函數本質上是類的實例。
這是否意味著,當你在類中定義一個方法時,得到的實際上是一個Function*的實例?不是的,在類中定義的方法是方法而不是函數。在repl中獨立定義的方法是Function*的實例。
類也可以擴展Function,這些類的實例可以使用()調用。
class AddOne extends Function1[Int, Int] {
def apply(m: Int): Int = m + 1
}
val plusOne = new AddOne()
plusOne(1) //2
可以使用更直觀快捷的extends (Int => Int)代替extends Function1[Int, Int]
class AddOne extends (Int => Int) {
def apply(m: Int): Int = m + 1
}
模式匹配
這是Scala中最有用的部分之一。
匹配值
val times = 1
times match {
case 1 => "one"
case 2 => "two"
case _ => "some other number"
}
使用守衛進行匹配
times match {
case i if i == 1 => "one"
case i if i == 2 => "two"
case _ => "some other number"
}
註意我們是怎樣獲取變量’i’的值的。
在最後一行指令中的_是一個通配符;它保證了我們可以處理所有的情況。 否則當傳進一個不能被匹配的數字的時候,你將獲得一個運行時錯誤。
匹配類型
你可以使用 match來分別處理不同類型的值。
def bigger(o: Any): Any = {
o match {
case i: Int if i < 0 => i - 1
case i: Int => i + 1
case d: Double if d < 0.0 => d - 0.1
case d: Double => d + 0.1
case text: String => text + "s"
}
}
匹配類成員
定義一個計算器,讓我們通過類型對它們進行分類。
def calcType(calc: Calculator) = calc match {
case _ if calc.brand == "HP" && calc.model == "20B" => "financial"
case _ if calc.brand == "HP" && calc.model == "48G" => "scientific"
case _ if calc.brand == "HP" && calc.model == "30B" => "business"
case _ => "unknown"
}
樣本類 Case Classes
使用樣本類可以方便得存儲和匹配類的內容。不用new關鍵字就可以創建它們。
case class Calculator(brand: String, model: String)
val hp20b = Calculator("HP", "20b")
樣本類基於構造函數的參數,自動地實現了相等性和易讀的toString方法。
val hp20b = Calculator("HP", "20b")
val hp20B = Calculator("HP", "20b")
hp20b == hp20B // true
樣本類也可以像普通類那樣擁有方法。
使用樣本類進行模式匹配
樣本類就是被設計用在模式匹配中的。讓我們簡化之前的計算器分類器的例子。
val hp20b = Calculator("HP", "20B")
val hp30b = Calculator("HP", "30B")
def calcType(calc: Calculator) = calc match {
case Calculator("HP", "20B") => "financial"
case Calculator("HP", "48G") => "scientific"
case Calculator("HP", "30B") => "business"
case Calculator(ourBrand, ourModel) => "Calculator: %s %s is of unknown type".format(ourBrand, ourModel)
}
最後一句也可以這樣寫
case Calculator(_, _) => "Calculator of unknown type"
或者我們完全可以不將匹配對象指定為Calculator類型
case _ => "Calculator of unknown type"
或者我們也可以將匹配的值重新命名。
case c
本文主要參考自Scala School-基礎知識(續)
Scala學習(二)——高級特性