2010-07-02 65 views
7

以下兩者有什麼區別?關於性狀的問題

1#

trait B extends A { 

} 

2#

trait B { self: A => 

} 

其中A是一個抽象類。

> >編輯:

請相對於可插拔飛行和嘎嘎叫的行爲解釋的Duck S上下面的例子:

abstract class Duck { 
    def fly(): Unit 
    def quack(): Unit 
    def swim() { 
    println("Woodoowoodoowoodoo...") 
    } 
} 

trait FlyingWithWings extends Duck { 
    override def fly() { 
    println("Me can fliez! :D") 
    } 
} 

trait FlyingNoWay { self: Duck => 
    def fly() { 
    println("Me cannot fliez! :(") 
    } 
} 

trait Quack extends Duck { 
    override def quack() { 
    println("Quack! Quack!") 
    } 
} 

trait MuteQuack { self: Duck => 
    def quack() { 
    println("<<Silence>>") 
    } 
} 

class MallardDuck extends Duck with FlyingWithWings with MuteQuack 

object Main { 
    def main(args: Array[String]) { 
    val duck = new MallardDuck 
    duck.fly() 
    duck.quack() 
    } 
} 

輸出:

我可以fliez! :d
< <沉默>>

+4

查看http://stackoverflow.com/questions/2224932/difference-between-trait-inheritance-and-self-type-annotation的副本,本身是http://stackoverflow.com/questions/1990948的副本/什麼是差別之間的自我類型和特質子類 – VonC 2010-07-02 07:03:23

回答

5

在第二種情況下,B不能用於期望A的地方,它只是被設計爲「附加」到某個A.因此,例如在第一種情況下,A可以是抽象的,B可以實現缺少的方法,使其成爲一個可實例化的類型。這在第二種情況下是不可能的,您需要一個「完整的A」,然後才能添加一些功能。

所以你可以想到一個「適合......」關係,而不是「是......」關係。

+0

哪一個應該是首選?爲什麼? – 2010-07-03 07:12:08

+0

這取決於你是否真的擴展了基本特徵。例如。如果你有一個特質圖,一個新的特性ColoredGraph顯然是「一種」(新類型)圖,應該擴展基本特徵。另一方面,如果使用方法findCycles添加特徵,則此特徵僅在與Graph一起使用時纔有意義,但它不會創建一種新的Graph,它只會添加一些功能,因此您會選擇第二個版本與這種情況下的自我類型。對於某些情況,差異不是很清楚,但有了一些經驗,您會看到哪個版本更適合您的設計。 – Landei 2010-07-03 10:19:16

+0

我不認爲你讓我。讓我試着重述一下。在我的問題中,「A」是一個「抽象類」,而不是「特質」。在我所包含的例子中,可以用兩種方式插入(或混合)行爲。 ('FlyingWithWings'使用擴展,而'MuteQuack'使用自我類型註釋。)那麼我應該什麼時候比另一個更喜歡一種方式,爲什麼? – 2010-07-03 13:41:21

1

在第一個例子是BA一個特例。第二種意思是,性狀B必須總是被混合到A(它可以是類,特徵或任何其他類型)或是其子類型。

+2

沒有一個特質也可以擴展一個類 – Aymen 2010-07-02 06:40:00

+0

我不知道,但我在REPL中試過它,它的工作原理。儘管如此,你仍然不能在直系血統中擁有多於一個的類,所以你不能獲得多重繼承(這就是爲什麼我雖然沒有擴展類的特性)。 – Theo 2010-07-02 06:54:04