Расширьте класс Scala, который расширяет упорядоченный

StackOverflow https://stackoverflow.com/questions/1818777

  •  10-07-2019
  •  | 
  •  

Вопрос

У меня возникли проблемы с расширением базового класса, который расширяет 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 кажется очень актуальным, но это меня немного теряет.

Это было полезно?

Решение

Вы можете использовать преобразование типа из 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 инвариантен.Он не может определить второй метод сравнения для реализации Order[B] с той же ошибкой типа, что и метод сравнения из Ordered[A].

В качестве альтернативы вы можете определить версии неявного типа от 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 принимает параметр.Параметр типа разрешен, но он работает так же, как и любой другой параметр.Когда вы расширяете его дважды, в базовом классе и в подклассе, вы не «импортируете» две версии Ordered.Вместо этого происходит линеаризация классов, и вы импортируете их только один раз.По этой причине вы не можете передать ему два разных параметра.

Теперь есть причина, почему TreeMap не требует subclass из Ordered, просто преобразование вашего класса в 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()

Вы можете поместить где-нибудь неявный 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 (спасибо, Кен)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top