8

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 関数にどのような制約を設定する必要があるかということです。

4

1 に答える 1

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))
}
于 2012-11-03T21:07:06.577 に答える