Scala特征:无法通过传递子

时间:2017-07-11 16:43:40

标签: scala traits mixins class-hierarchy

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

3 个答案:

答案 0 :(得分:0)

因此,问题的根本原因是您的根特征中有一个抽象的valval按顺序初始化(并非一次性完成),此订单有时可能会令人惊讶 - 例如如果你覆盖这些null或者从同一个班级的任何地方获得前向引用,你会看到val你不期望它们的位置。

因此,避免此类问题的经验法则很简单:总是将def用于抽象成员

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

此外,我试图了解您尝试使用此代码实现的目标,并且我认为您对Scala中的多重继承的理解可能是错误的。即使您在根特征中使用lazy valdef内也只会有carModelcarModelStatement的一个值 - 为依赖于的所有内容产生相同的字符串这个属性。

答案 1 :(得分:0)

我认为你不能以你想要的方式“存储”特征成员的价值。

但这有效:

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

答案 2 :(得分:0)

我也遇到过类似的情况。使用this.解决了这个问题。

trait CarFamily {
var carModel: String = "test" //assign some string and change val to var
def carModelStatement: String = s"The model of the car is ${carModel}"
}

trait Honda extends CarFamily {
this.carModel=  "honda" //pass the actual string value
}