Scala特征:无法通过传递子元素中的值来获取抽象父特征值

这个例子是我试图解决的更大问题的模型 . 顶部的层次结构是抽象特征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)

2 years ago

所以问题的根本原因是你的根特征中有一个抽象的 val . val s按顺序初始化(不是一次全部),这个顺序有时可能会令人惊讶 - 例如如果你覆盖这些 val 或者从同一个类的任何地方获得前向引用,你会看到 null s你不会指望它们 .

因此,避免此类问题的经验法则很简单:始终使用 def 作为抽象成员 .

此规则增加了一个额外的好处,即在用于实现/覆盖这些字段的成员类型中具有灵活性:您可以使用 defvalvarlazy val 扩展 def (后者有时非常有用) .

此外,我试图了解你认为你对Scala中的多重继承的理解可能是错误的 . [277846]即使你在根特征中使用了 def ,在 allModels 中也只有一个 carModelcarModelStatement 的值 - 为依赖于这个属性的所有内容产生相同的字符串 .

2 years ago

我不认为你可以按照你想要的方式将 Value “存储”在特质成员中 .

这有效:

trait CarFamily {
  def carModelStatement(carModel: String): String = s"The model of the car is ${carModel}"
}

trait Honda extends CarFamily {
  val honda: String
  def hondaModelStatement : String = carModelStatement("honda")
}

trait Civic extends CarFamily {
  val civic: String
  def civicModelStatement : String = carModelStatement("civic")
}

trait Volvo extends CarFamily {
  val volvo: String
  def volvoModelStatement : String = carModelStatement("volvo")
}

object allModels extends Volvo with Civic with Honda {
  val volvo = "Volvo X3"
  val civic = "Civic Family"
  val honda = "Honda Extreme"

}

allModels.volvoModelStatement 
allModels.civicModelStatement 
allModels.hondaModelStatement

输出:

res0: String = The model of the car is volvo
res1: String = The model of the car is civic
res2: String = The model of the car is honda