4

Ordered[Base] を拡張する基本クラスの拡張に問題があります。私の派生クラスは Ordered[Derived] を拡張できないため、TreeMap のキーとして使用できません。TreeMap[Base] を作成し、Derived で比較をオーバーライドするだけで機能しますが、それは私が望むものではありません。派生クラスをキーにできるようにしたいです。これを回避する方法はありますか?

case class A(x: Int) extends Ordered[A] {
  def compare(that: A) = x.compare(that.x)
}

// Won't compile
//  case class B(val y : Int) extends A(1) with Ordered[B] {
//    def compare(that: B) = x.compare(that.x) match {
//      case 0 => y.compare(that.y)
//      case res => res
//    }
//  }

// Compiles but can't be used to define a TreeMap key
case class B(y: Int) extends A(1) {
  override def compare(that: A) = that match {
    case b: B => x.compare(b.x) match {
      case 0 => y.compare(b.y)
      case res => res
    }
    case _: A => super.compare(that)
  }
}

def main(args: Array[String]) {
  TreeMap[B, Int]() // Won't compile
}

編集

scala メーリング リストでのこの議論は非常に関連性が高いように思えますが、少し迷ってしまいます。

4

3 に答える 3

4

B から Ordered[B] への型変換を使用できます。

class OrderedB(me : B) extends Ordered[B]{
    def compare(that: B) = me compare that
}
collection.immutable.TreeMap.empty[B, Int](new OrderedB(_))

B は常に A のサブタイプでなければならないと思います。これは、型 A が不変である Order[A] を意味します。Ordered[A] からの比較メソッドと同じタイプ消去で Order[B] を実装するための 2 番目の比較メソッドを定義することはできません。

あるいは、B から Ordered[B] への暗黙の型バージョンを定義することもできます。

implicit def orderedA2orderedB[B <: A with Ordered[A]](b : B) : Ordered[B] = b.asInstanceOf[Ordered[B]]
collection.immutable.TreeMap[B, Int]()

これは有効なはずです。キャストなしで型システムでこれを表現する方法を知りません。

于 2009-11-30T10:09:08.490 に答える
3

特性Orderedはパラメーターを取ります。当然のことながら、型パラメーターですが、他のパラメーターと同じように機能します。基本クラスとサブクラスで 2 回拡張すると、2 つのバージョンのOrdered. 代わりに、クラスの線形化が行われ、一度だけインポートします。そのため、2 つの異なるパラメーターを渡すことはできません。

ここで、クラスから of への変換だけで、of をTreeMap必要としない理由があります。まさにそんなことを可能にすることです。これらを直接拡張する代わりに、それらを暗黙的に指定する必要があります。subclassOrderedOrdered

scala> class A(val x: Int)
defined class A

scala> class B(x : Int, val y : Int) extends A(x)
defined class B

scala> import scala.collection.immutable.TreeMap
import scala.collection.immutable.TreeMap

scala> class AOrd(a: A) extends Ordered[A] {
     |   def compare(that: A) = a.x.compare(that.x)
     | }
defined class AOrd

scala> object AOrd {
     | implicit def toAOrd(a: A) = new AOrd(a)
     | }
defined module AOrd

scala> class BOrd(b: B) extends Ordered[B] {
     |   def compare(that: B) = b.x.compare(that.x) match {
     |     case 0 => b.y.compare(that.y)
     |     case res => res
     |   }
     | }
defined class BOrd

scala> object BOrd {
     | implicit def toBOrd(b: B) = new BOrd(b)
     | }
defined module BOrd

scala> import AOrd._
import AOrd._

scala> import BOrd._
import BOrd._

scala> TreeMap[B, Int]()
res1: scala.collection.immutable.SortedMap[B,Int] = Map()
于 2009-11-30T15:24:56.333 に答える
2

次のように、スコープ内のどこかに暗黙のOrdering[B]を配置できます。

  object BOrdering extends Ordering[B] {
    def compare(a: B, b: B) = a.compare(b)
  }
  implicit val bo = BOrdering
  TreeMap[B, Int]() // Now it works!

編集:これはScala 2.8のみです(ありがとう、Ken)

于 2009-11-30T10:58:44.990 に答える