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 的子类型,这意味着 Order[A] 类型 A 是不变的。它不能定义第二个比较方法来实现具有与 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]()

这应该是有效的。我不知道在没有强制转换的类型系统中表达这一点的方法。

于 2009-11-30T10:09:08.490 回答
3

该特征Ordered需要一个参数。一个类型参数,被授予,但它的工作方式与任何其他参数一样。当您在基类和子类中扩展它两次时,您并没有“导入”两个版本的Ordered. 相反,会发生类的线性化,并且只导入一次。因此,您不能将两个不同的参数传递给它。

TreeMap现在,不需要 a subclassof是有原因的Ordered,只需从您的类转换为 an 即可Ordered。正是让这样的事情成为可能。而不是直接扩展这些东西,你应该为它们隐含:

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 回答