这个例子是我试图解决的更大问题的模型 . 顶部的层次结构是抽象特征CarFamily,然后从CarFamily延伸出3个抽象特征,即本田,思域和沃尔沃 . 我的目标是能够在从这3个特征扩展的实例中为每个子特征调用carModelStatement .
但是,正如您可以看到结果一样,这些语句都返回“汽车模型为空” . 所以val volvo,honda,civic没有传到我对Scala的新手 . 想知道我错过了什么,或者是否有其他设计可以得到我想要的东西 . 谢谢!
trait CarFamily {
val carModel: String
def carModelStatement: String = s"The model of the car is ${carModel}"
}
trait Honda extends CarFamily {
val honda: String
override val carModel: String = honda
def hondaModelStatement : String = carModelStatement
}
trait Civic extends CarFamily {
val civic: String
override val carModel: String = civic
def civicModelStatement : String = carModelStatement
}
trait Volvo extends CarFamily {
val volvo: String
override val carModel: String = volvo
def volvoModelStatement : String = carModelStatement
}
object allModels extends Volvo with Civic with Honda {
val volvo = "Volvo X3"
val civic = "Civic Family"
val honda = "Honda Extreme"
}
allModels.volvoModelStatement //res1: String = The model of the car is null
allModels.civicModelStatement // res2: String = The model of the car is null
allModels.hondaModelStatement // res3: String = The model of the car is null
2 回答
所以问题的根本原因是你的根特征中有一个抽象的
val
.val
s按顺序初始化(不是一次全部),这个顺序有时可能会令人惊讶 - 例如如果你覆盖这些val
或者从同一个类的任何地方获得前向引用,你会看到null
s你不会指望它们 .因此,避免此类问题的经验法则很简单:始终使用
def
作为抽象成员 .此规则增加了一个额外的好处,即在用于实现/覆盖这些字段的成员类型中具有灵活性:您可以使用
def
,val
,var
或lazy val
扩展def
(后者有时非常有用) .此外,我试图了解你认为你对Scala中的多重继承的理解可能是错误的 . [277846]即使你在根特征中使用了
def
,在allModels
中也只有一个carModel
和carModelStatement
的值 - 为依赖于这个属性的所有内容产生相同的字符串 .我不认为你可以按照你想要的方式将 Value “存储”在特质成员中 .
这有效:
输出: