我正在尝试为正在编写的库构建以下类型结构,但是在类型系统方面遇到了麻烦。
CarLike
trait CarLike[T, C <: CarLike[T,C]] {
val parts: Seq[T]
def crash(other: C, speed: Int): C
//... other methods
}
SimpleCar
class SimpleCar[T](val parts: Seq[T]) extends CarLike[T, SimpleCar[T]] {
def crash(other: SimpleCar[T], speed: Int) = {
//Some logic to crash with the other car
val newParts = damage(parts) //parts have changed
new SimpleCar(newParts)
}
//...other methods
}
SportsCar
class SportsCar(val sParts: Seq[String]) extends SimpleCar[String](sParts){
override def crash(other: SimpleCar[String], speed: Int): SimpleCar[String] = {
//Some other logic for crashing a sport car
val newParts = damage(parts) //parts have changed
new SportsCar(newParts)
}
//...other methods
}
崩溃者
case class Crasher[T, C <: CarLike[T,C]](
partsDamager: T => T,
carChecker: C => Seq[T]
/*... more parameters*/
){
def test(cycles:Int) = {
//Some logic to run a crash of two cars
}
}
代码
//...
val crasher = Crasher[String, SportsCar](
(s: String) => s.tail,
(c: SportsCar) => c.parts.filter(p => p.length > 0)
/*Many arguments*/
)
crasher.test(20)
//...
该想法是允许库的用户能够在使用默认SimpleCar
和实现自己的CarLike
实现之间进行选择。
另外,用户可以选择汽车零件的类型。在这个简单的示例中,这些部分是String
,但可以轻松地成为自定义类,可以在自定义类的crash
方法中加以利用。
编译时,出现以下编译错误:
type arguments [String,my.package.SportsCar] do not conform to method apply's type parameter bounds [T,C <: crashing.CarLike[T,C]]
val crasher = Crasher[String, SportsCar](
很显然,这里我缺少一些东西。为何编译器不同意SportsCar
是CarLike
的合法子类型?
答案 0 :(得分:3)
跑车不是CarLike[String, SportsCar]
,而是CarLike[String, SimpleCar[String]]
。请注意,SportsCar extends SimpleCar[String]
没什么用,因为CarLike
在C
中不是协变的。
您无法真正在CarLike
中使C
协变,因为其crash
方法接受C
。相反,您可以将SimpleCar[String]
传递给Crasher
(毕竟,跑车可能会与其他车辆相撞,对吗?):
val crasher = Crasher[String, SimpleCar[String]](
s => s.tail,
c => c.parts.filter(p => p.length > 0)
)
或者,您可以修改Crasher
以使用另一个类型参数:
case class Crasher[T, C <: CarLike[T, C], X <: C](partsDamager: T => T,
carChecker: X => Seq[T]) {
// ...
}
val crasher = Crasher[String, SimpleCar[String], SportsCar](
s => s.tail,
c => c.parts.filter(p => p.length > 0)
)