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 の境界 >: Nothing <: A[Y] は型 _ の宣言された境界よりも厳密です >: Nothing <: Z forSome { type Z <: A[Z] } val myList = emptyList[B] ()
私に_ <: Z forSome { type Z <: A[Z] }
は、確かに少なくとも同じくらい厳密であるように思えますY <: A[Y]
が、何かが欠けているかもしれません。
問題は、B を正しく処理するために emptyList 関数にどのような制約を設定する必要があるかということです。