Scala:Object在运行时继承

时间:2016-12-20 00:07:05

标签: scala traits case-class

我在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

2 个答案:

答案 0 :(得分:3)

对于第一个问题,"为什么我们可以继承这里?",这只是因为你被允许。这创建了一个继承自AComponent和装饰器的对象,如果你编译它,你会发现有一个匿名类,它是持有这个对象的类而生成的。代码。

其次,关于你需要使用new的原因。 AComponent(x)AComponent.apply(x)的语法糖。 (直接){strong>糖为new AComponent(x)AComponent.applyobject 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/

来解决