在 Scala中Trait 為重用代碼的一個基本單位。一個 Traits 封裝了方法和變量,和 Interface 相比,它的方法可以有實現(xiàn),這一點有點和抽象類定義類似。但和類繼承不同的是,Scala 中類繼承為單一繼承,也就是說子類只能有一個父類。當(dāng)一個類可以和多個 Trait 混合,這些 Trait 定義的成員變量和方法也就變成了該類的成員變量和方法,由此可以看出 Trait 集合了 Interface 和抽象類的優(yōu)點,同時又沒有破壞單一繼承的原則。
下面我們來看看Trait的基本用法:
定義一個 Trait 的方法和定義一個類的方法非常類似,除了它使用 trait 而非 class 關(guān)鍵字來定義一個 trait。
trait Philosophical{
def philosophize() {
println("I consume memeory, therefor I am!")
}
}
這個 Trait 名為 Philosophical。它沒有聲明基類,因此和類一樣,有個缺省的基類 AnyRef。它定義了一個方法,叫做 philosophize。這是個簡單的 Trait,僅夠說明 Trait 如何工作。
一但定義好 Trait,它就可以用來和一個類混合,這可以使用 extends 或 with 來混合一個 trait。例如:
class Frog extends Philosophical{
override def toString="gree"
}
這里我們使用 extends 為 Frog 添加 Philosophical Trait 屬性,因此 Frog 缺省繼承自 Philosophical 的父類 AnyRef,這樣 Frog 類也具有了 Philosophical 的性質(zhì)(因此 Trait 也可以翻譯成特質(zhì),但后面我們還是繼續(xù)使用 Trait 原文)。
scala> val frog = new Frog
frog: Frog = green
scala> frog.philosophize
I consume memeory, therefor I am!
可以看到 Frog 添加了 Philosophical(哲學(xué)性)也具有了哲學(xué)家的特性,可以說出類似“我思故我在”的話語了。和 Interface 一樣,Trait 也定義一個類型,比如:
scala> val phil:Philosophical = frog
phil: Philosophical = green
scala> phil.philosophize
I consume memeory, therefor I am!
變量 phil 的類型為 Philosophical。
如果你需要把某個 Trait 添加到一個有基類的子類中,使用 extends 繼承基類,而可以通過 with 添加 Trait。比如:
class Animal
class Frog extends Animal with Philosophical{
override def toString="green"
}
還是和 Interface 類似,可以為某個類添加多個 Trait 屬性,此時使用多個 with 即可,比如:
class Animal
trait HasLegs
class Frog extends Animal with Philosophical with HasLegs{
override def toString="green"
}
目前為止你看到的例子中,類 Frog 都繼承了 Philosophical 的 philosophize 實現(xiàn)。此外 Frog 也可以重載 philosophize 方法。語法與重載基類中定義的方法一樣。
class Animal
trait HasLegs
class Frog extends Animal with Philosophical with HasLegs{
override def toString="green"
def philosophize() {
println("It ain't easy being " + toString + "!")
}
}
因為 Frog 的這個新定義仍然混入了特質(zhì) Philosophize,你仍然可以把它當(dāng)作這種類型的變量使用。但是由于 Frog 重載了 Philosophical 的 philosophize 實現(xiàn),當(dāng)你調(diào)用它的時候,你會得到新的回應(yīng):
scala> val phrog:Philosophical = new Frog
phrog: Philosophical = green
scala> phrog.philosophize
It ain't easy being green!
這時你或許推導(dǎo)出以下結(jié)論:Trait 就像是帶有具體方法的 Java 接口,不過其實它能做的更多。Trait 可以,比方說,聲明字段和維持狀態(tài)值。實際上,你可以用 Trait 定義做任何用類定義做的事,并且語法也是一樣的,除了兩點。第一點,Trait 不能有任何“類”參數(shù),也就是說,傳遞給類的主構(gòu)造器的參數(shù)。換句話說,盡管你可以定義如下的類:
class Point(x: Int, y: Int)
但下面的 Trait 定義直接報錯:
scala> trait NoPoint(x:Int,y:Int)
<console>:1: error: traits or objects may not have parameters
trait NoPoint(x:Int,y:Int)
更多建議: