我正在尝试创建一个使用CRTP按类型参数化的特征列表,并且无法弄清楚如何表达类型约束。以下是一些说明问题的示例代码:
trait A[X] {
def x: X
}
trait B[Y <: A[Y]] {
def y(i: Int): Y
}
case class C(i: Int) extends A[C] {
def x = C(i)
}
case class D(i: Int) extends A[D] {
def x = D(i)
}
case class E() extends B[C] {
def y(i: Int) = C(i)
}
case class F() extends B[D] {
def y(i: Int) = D(i)
}
object Program extends App {
def emptyList[X[_ <: Z forSome { type Z <: A[Z] } ]]() = collection.mutable.ListBuffer.empty[X[_]]
val myList = emptyList[B]()
myList += E()
myList += F()
println(myList.map(_.y(2).x))
}
所以我在这里尝试创建一个符合B特征的对象列表。但是,此代码将无法编译,并出现以下错误:
类型参数(B)的种类不符合预期种类的参数(类型X)。 B的类型参数与类型X的预期参数不匹配:类型Y的边界&gt;:Nothing&lt ;: A [Y]比类型_的声明边界更严格&gt;:Nothing&lt;:Z forSome {type Z&lt;:A [Z ] val myList = emptyList [B]()
对我而言,似乎_ <: Z forSome { type Z <: A[Z] }
确实至少与Y <: A[Y]
一样严格,但也许我错过了一些东西。
所以问题是 - 对于正确处理B的空列表函数应该有什么约束?
答案 0 :(得分:4)
经过一些反复试验,我得到了它的工作。注意:编译器告诉我们A [+ X]和B [+ Y]中的类型参数必须是协变的。
trait A[+X] {
def x: X
}
trait B[+Y <: A[Y]] {
def y(i: Int): Y
}
case class C(i: Int) extends A[C] {
def x = C(i)
}
case class D(i: Int) extends A[D] {
def x = D(i)
}
case class E() extends B[C] {
def y(i: Int) = C(i)
}
case class F() extends B[D] {
def y(i: Int) = D(i)
}
object Test extends App {
def emptyList[X[Y <: A[Y]]] = collection.mutable.ListBuffer.empty[X[Y forSome {type Y <: A[Y]} ]]
val myList = emptyList[B]
myList += E()
myList += F()
println(myList.map(_.y(2).x))
}