2011-10-08 70 views
3

爲什麼x.func下方回報"B extends B extends B"? 如何安排此代碼以便返回"B extends A extends Base"行爲鏈斯卡拉超級性狀

trait Base { 
    def name = "Base" 
    def func = name 
} 

trait A extends Base { 
    override def name = "A" 
    override def func = name + " extends " + super.func 
} 

trait B extends Base { 
    override def name = "B" 
    override def func = name + " extends " + super.func 
} 

val x = new Base with A with B 
println(x.func) 

更新:一種安排可能如下。它現在在AB中具有相同的定義func1。如果我嘗試將其移動到Derived類別,則不起作用。任何想法如何刪除重複的func1

trait Base { 
    def name = "Base" 
    def func1(s: String) = s 
} 

trait Derived extends Base { 
    def func = func1(name) 
} 

trait A extends Derived { 
    override def func1(s: String) = s + " extends " + super.func1(super.name) 
    override def name = "A" 
} 

trait B extends Derived { 
    override def func1(s: String) = s + " extends " + super.func1(super.name) 
    override def name = "B" 
} 

val x = new Base with A with B 
println(x.func) 
+0

一些更多的澄清:在真實場景中的名字是不能FUNC內聯一個獨立的方法。另外,我正在試驗以查看func的定義是否可以在所有擴展Base的特徵中完全相同。 –

回答

10

我想繼承順序,實際上可能是你正在尋找的人。如果更換" extends "有一個顯示哪一種方法,其中特徵被稱爲:

trait Base { 
    def name = "Base" 
    def func = "Base." + name 
} 

trait A extends Base { 
    override def name = "A" 
    override def func = name + " A.extends " + super.func 
} 

trait B extends Base { 
    override def name = "B" 
    override def func = name + " B.extends " + super.func 
} 

val x = new Base with A with B 
println(x.func) 
// B B.extends B A.extends Base.B 

這只是name總是"B"。換句話說:

trait Base { def func = "Base" } 
trait A extends Base { override def func = "A extends " + super.func } 
trait B extends Base { override def func = "B extends " + super.func } 
val x = new Base with A with B 
println(x.func) 
// B extends A extends Base 

這是你想要的...

你的榜樣的完整線性化:

Object, B, A, Base, ScalaObject, AnyRef, Any 

(見http://ofps.oreilly.com/titles/9780596155957/ScalaObjectSystem.html#Linearization關於如何找出一個實際的解釋線性化)

編輯回答評論:爲什麼name總是返回"B"?這是因爲def name方法被性狀B覆蓋以返回"B"。這是繼承的整點,能在是在子類中提煉超類行爲,以便使用:

trait Legs { 
    def legs: Int 
    def printLegs() { println("I have " + legs + " legs") } 
} 

class Dog extends Legs { def legs = 4 } 
class Chicken extends Legs { def legs = 2 } 

new Dog printLegs 
// I have 4 legs 
new Chicken printLegs 
// I have 2 legs 

legs的特質Legs不是單獨一個legsDog因比,如果你是指它在LegsDog ......同樣,你def name總是返回"B"如果你的對象是一個B

它看起來像你想用的名字作爲私有方法:

trait Base { 
    private def _name() = "Base" 
    def func = _name 
} 
trait A extends Base { 
    private def _name() = "A" 
    override def func = _name + " extends " + super.func 
} 
trait B extends Base { 
    private def _name() = "B" 
    override def func = _name + " extends " + super.func 
} 
val x = new Base with A with B 
println(x.func) 
// B extends A extends Base 

我發現,如果沒有一個明確的對象模型,使用特點和繼承迅速變得複雜。我假設你已對此示例進行了清理/簡化,以便使用通用名稱,如A, B, Base, func,以便您瞭解問題的核心,但另一方面,它並不能讓我瞭解可以做什麼更改以使其適用於您。正如你問我已經安排了代碼,以便它打印"B extends A extends Base"。我敢肯定,還有一些其他限制條件不成問題,爲什麼它不適合你。

+0

「它的名字總是B」。這是問題的關鍵。這是爲什麼?感謝您提出的解決方案,但我確實希望func的定義對於每個特徵都是相同的。 –

+0

特徵的超級調用在運行時解析。通過說'特質A擴展B',你聲明'A'只能被混合到擴展'B'的東西中。沒有辦法知道'A'是否被混合到直接擴展'B'的類中,或者在幾個可堆棧特徵('... with A with B')之後。因此,在特質聲明的這一點上,不可能確定哪個特質將會在這個特定修改的「上方」,或者換句話說,就是您所超級召喚將會導致的修改。 – agilesteel

+0

@huynhjl,請參閱問題的更新。現在試圖擺脫func1的重複。 –