2010-07-02 56 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