我在Scala中有以下代码:
trait Component {
def state : String
def name: String
}
case class AComponent( id : String) extends Component {
def state = name + ":" + id
def name = "A"
}
trait ComponentDecoratorA extends Component {
abstract override def name = "ByADecorated:" + super.name
}
trait ComponentDecoratorB extends Component {
abstract override def name = "ByBDecorated:" + super.name
}
object Run
{
def main (args : Array[String]) = {
val c = new AComponent ("42") // static decoration
with ComponentDecoratorA with ComponentDecoratorB
println( c.state)
}
输出是:
的 ByBDecorated:ByADecorated:A:42
我是Scala的新手,但我知道我们可以从对象创建中的trait继承来限制对象的特性。但正如我所理解的那样,我们在创建对象时继承了ComponentDecoratorA和ComponentDecoratorB。但为什么我们不会因为名称方法而发生冲突?输出显示调用所有三个类的名称方法。怎么会发生这种情况?
val c = new AComponent ("42") // static decoration
with ComponentDecoratorA with ComponentDecoratorB
为什么我们需要new
虽然我们正在使用案例类?
它如何得到结果 ByBDecorated:ByADecorated:A:42 ?
答案 0 :(得分:3)
对于第一个问题,"为什么我们可以继承这里?",这只是因为你被允许。这创建了一个继承自AComponent
和装饰器的对象,如果你编译它,你会发现有一个匿名类,它是持有这个对象的类而生成的。代码。
其次,关于你需要使用new
的原因。 AComponent(x)
是AComponent.apply(x)
的语法糖。 (直接){strong>糖为new AComponent(x)
。 AComponent.apply
是object AComponent
中自动生成的方法,如下所示:
object AComponent extends (String => AComponent) {
// Overrides the one in (^ is sugar for >)Function1[String, AComponent]
override def apply(id: String): AComponent = new AComponent(id)
}
调用它只会给你一个普通的AComponent
,并且不可能混合特征,因为只有在定义新类型(例如class Foo extends A with B
)或者使用构造函数(例如new AComponent("42") with ComponentDecoratorA with ComponentDecoratorB
)。
最后,编译器执行称为type linearization到#34; flatten"特征和类的层次结构从某个序列继承。对于AComponent with CDA with CDB
,线性化顺序为:
Component <- AComponent <- CDA <- CDB
允许CDB
在覆盖super.name
本身时调用name
的内容是abstract override
。这意味着CDB
同时覆盖了name
,并且还要求其他人为super.name
提供实施。这在stackable trait模式中很有用。
调用方法时,会对该顺序执行从右到左的搜索,以查找应该调用的内容。因此CDB#name
调用CDA#name
来电AComponent#name
,然后CDA#name
预先&#34; ByADecorated:&#34;,然后CDB#name
预先&#34; ByBDecorated:&#34;
此外,正如问题标题所暗示的那样,在运行时混合特征是impossible(非常,非常困难且非常危险)。这都是在编译时通过生成匿名类来完成的。
答案 1 :(得分:0)
当你说new Class1 with Trait1
时,你正在用Java创建一个等效的匿名类。例如。在Java中你可以说new Class1(){ /* add additional implementation details here*/ }
根据组合this.name + this.super.name
字符串时包含的顺序,这被称为“菱形问题”,并通过Scala称之为“类型线性化:”https://www.safaribooksonline.com/blog/2013/05/30/traits-how-scala-tames-multiple-inheritance/