首页 文章

Scala:Object在运行时继承

提问于
浏览
0

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

  • 3

    对于第一个问题,"why can we inherit here?",这只是因为你被允许 . 这将创建一个继承自 AComponent 和装饰器的对象,如果您编译它,则'll find there'是一个生成的匿名类,其中包含此对象's class' s代码 .

    其次,为什么你需要使用 new . AComponent(x)AComponent.apply(x) 的语法糖 . It is not (直接) sugar for 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到"flatten"的特征和类的层次结构,这些特征继承自序列 . 对于 AComponent with CDA with CDB ,线性化顺序为:

    Component <- AComponent <- CDA <- CDB
    

    允许 CDB 在覆盖 name 时调用 super.name 的事情是 abstract override . 这意味着 CDB 同时覆盖 name ,并且还要求其他人提供 super.name 的实现 . 这在stackable trait模式中很有用 .

    调用方法时,将对该顺序执行从右到左的搜索,以查找应该调用的内容 . 所以 CDB#name 调用 CDA#name 调用 AComponent#name ,然后 CDA#name prepends "ByADecorated:",然后 CDB#name 调用"ByBDecorated:" .

    而且,正如问题 Headers 所暗示的那样,在运行时混合特征是非常困难的,也是非常危险的 . 这都是在编译时通过生成匿名类完成的 .

  • 0

    当你说 new Class1 with Trait1 时,你正在用Java创建一个等效的匿名类 . 例如 . 在Java中你可以说 new Class1(){ /* add additional implementation details here*/ }

    根据组合 this.name + this.super.name 字符串时包含的顺序,这被称为"diamond problem",并由Scala调用"type linearization:" https://www.safaribooksonline.com/blog/2013/05/30/traits-how-scala-tames-multiple-inheritance/解决

相关问题