順序付けを拡張するScalaクラスを拡張する
-
10-07-2019 - |
質問
Ordered [Base]を拡張する基本クラスの拡張に問題があります。私の派生クラスはOrdered [Derived]を拡張できないため、TreeMapのキーとして使用できません。 TreeMap [Base]を作成し、Derivedでcompareをオーバーライドするだけで機能しますが、それは私が望むものではありません。派生クラスをキーとして使用できるようにしたいと思います。これを回避する方法はありますか?
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メーリングリストのこのディスカッション関連性が高いが、少し気が滅入る。
解決
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は常にOrder [A] whoesタイプAが不変であることを意味するAのサブタイプである必要があると思います。 2番目の比較メソッドを定義して、Ordered [A]の比較メソッドと同じタイプのエラーを持つOrder [B]を実装することはできません。
別の方法として、BからOrdered [B]への暗黙的なタイプバージョンを定義できます。
implicit def orderedA2orderedB[B <: A with Ordered[A]](b : B) : Ordered[B] = b.asInstanceOf[Ordered[B]]
collection.immutable.TreeMap[B, Int]()
これは有効でなければなりません。これをキャストなしの型システムで表現する方法を知りません。
他のヒント
特性 Ordered
はパラメーターを取ります。許可された型パラメーターですが、他のパラメーターと同様に機能します。基本クラスとサブクラスで2回拡張すると、「インポート」ではなくなります。 Ordered
の2つのバージョン。代わりに、クラスの線形化が行われ、一度だけインポートします。そのため、2つの異なるパラメーターを渡すことはできません。
今、 TreeMap
が Ordered
の subclass
を必要とせず、クラスから >注文済み
。まさにそのようなことを可能にすることです。これらのものを直接拡張する代わりに、それらを暗黙的にすべきです:
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()
次のように、暗黙的な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)