【问题标题】:Type system not allowing subtype as a type constructor类型系统不允许子类型作为类型构造函数
【发布时间】:2019-07-24 14:02:02
【问题描述】:

我正在尝试为我正在编写的库构建以下类型结构,但我遇到了类型系统问题。

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
}

跑车

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](

很明显,我在这里缺少一些东西。为什么编译器不同意SportsCarCarLike 的合法子类型?

【问题讨论】:

  • 您可能过于简化了在 SO 上发布的代码。忽略 CrasherCode 部分,我无法让 SportsCar 编译,原因可能与您看到的错误相关,也可能不相关.
  • @jwvh,谢谢。我实际上编译了我的示例代码,但由于帖子中显示的错误而失败。

标签: scala generics types


【解决方案1】:

跑车不是CarLike[String, SportsCar],而是CarLike[String, SimpleCar[String]]。请注意SportsCar extends SimpleCar[String],但这无济于事,因为CarLikeC 中不是协变的。

你不能真正使CarLikeC 中协变,因为它的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)
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-14
    • 2018-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-07
    • 1970-01-01
    相关资源
    最近更新 更多