我在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 回答
对于第一个问题,"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.apply
是object AComponent
中自动生成的方法,如下所示:调用它只会给你一个普通的旧的
AComponent
,并且不可能混合特征,因为只有在定义新类型(例如class Foo extends A with B
)或使用构造函数(例如new AComponent("42") with ComponentDecoratorA with ComponentDecoratorB
)时才可以 .最后,编译器执行一些称为type linearization到"flatten"的特征和类的层次结构,这些特征继承自序列 . 对于
AComponent with CDA with 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 所暗示的那样,在运行时混合特征是非常困难的,也是非常危险的 . 这都是在编译时通过生成匿名类完成的 .
当你说
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/解决