我有一个类需要2个特征,这两个特征都需要相同的特性。我如何在这种情况下添加它
class RandomTest extends AbstractTestCase {
"asdasd" should "asdsda" in {
val a = new Application with XYZAppName with Session with MetricsPublisher
a.a()
}
abstract class Application extends Session with MetricsPublisher {
println("Application")
def a() : Unit = { println("application.a")}
}
trait RequiredAppContext {
println("RequiredAppContext")
val appName : String
}
trait MetricsPublisher extends RequiredAppContext {
this:RequiredAppContext =>
println("MetricsPublisher")
}
trait Session extends RequiredAppContext{
this:RequiredAppContext =>
println("Session")
lazy val appNameoverload = func(appName)
def func(value:String ) {println("appNameoverload "+appName)}
}
// implmentations
trait XYZAppName extends RequiredAppContext {
println("XYZAppName")
override val appName = "xyz"
}
}
以下是该程序的输出:
[scalatest] RequiredAppContext
[scalatest] Session
[scalatest] MetricsPublisher
[scalatest] Application
[scalatest] XYZAppName
[scalatest] application.a
将XYZAppName初始化移至Session之前的最佳方法是什么?
答案 0 :(得分:1)
Scala的线性化算法,管理特征图初始化顺序和解决钻石继承问题,以声明顺序遍历(非循环)继承图,满足初始化父节点的要求,但省略已经初始化的所有重复项。这里的问题是,要初始化某个类,首先需要初始化它的基类,以及扩展它的所有特性。 Scala甚至不允许在extends
或new
之后的任何位置指定基类 - 您只能使用with
添加特征。对于({1}}基类的(匿名)类是a
:
Application
因此,您唯一的选择是修改您的继承层次结构,将a.type
-> Application
-> Session
-> RequiredAppContext
-> MetricsPublisher
-> RequiredAppContext // omitted
-> XYZAppName
-> RequiredAppContext // omitted
-> Session // omitted
-> RequiredAppContext // parent omitted
-> MetricsPublisher // omitted
-> RequiredAppContext // parent omitted
转换为特征,然后在Application
的定义中使用XYZAppName
对其进行重新排序:
a
然而,该解决方案无法涵盖所有可能的情况 - 如果您的抽象类具有构造函数,则无法将其转换为特征(有ongoing work在未来版本的Scala中允许特征参数,但是它还远未完成)。如果基类是在外部代码中定义的,那么它也不是一个选项。