Extiende la clase scala que se extiende ordenada
-
10-07-2019 - |
Pregunta
Tengo problemas para extender una clase base que extiende Ordered [Base]. Mi clase derivada no puede extender Ordered [Derived], por lo que no se puede usar como clave en un TreeMap. Si creo un TreeMap [Base] y luego anulo la comparación en Derivado, eso funciona pero no es lo que quiero. Me gustaría poder tener la clase derivada como clave. ¿Hay alguna forma de evitar esto?
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
}
Editar
Esta discusión en la lista de correo scala parece ser muy relevante pero me pierde un poco.
Solución
Puede usar una conversión de tipo de B a Ordenada [B]:
class OrderedB(me : B) extends Ordered[B]{
def compare(that: B) = me compare that
}
collection.immutable.TreeMap.empty[B, Int](new OrderedB(_))
Creo que B siempre tiene que ser un subtipo de A, lo que implica que la Orden [A] cuyo tipo A es invariante. No puede definir un segundo método de comparación para implementar la Orden [B] con el mismo tipo de error que el método de comparación de la Orden [A].
Alternativamente, puede definir versiones de tipo implícito de B a Ordenado [B]:
implicit def orderedA2orderedB[B <: A with Ordered[A]](b : B) : Ordered[B] = b.asInstanceOf[Ordered[B]]
collection.immutable.TreeMap[B, Int]()
Esto debería ser válido. No conozco una forma de expresar esto en el sistema de tipos sin conversiones.
Otros consejos
El rasgo Ordenado
toma un parámetro. Un parámetro de tipo, otorgado, pero funciona como cualquier otro parámetro. Cuando lo extiende dos veces, en la clase base y en la subclase, no está importando " dos versiones de Ordered
. En cambio, se lleva a cabo la linealización de las clases, y solo se importa una vez. Por esa razón, no puede pasarle dos parámetros diferentes.
Ahora, hay una razón por la cual TreeMap
no requiere una Ordenado
, solo una conversión de su clase a un
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()
Podría poner un orden implícito [B] dentro del alcance en algún lugar, como este:
object BOrdering extends Ordering[B] {
def compare(a: B, b: B) = a.compare(b)
}
implicit val bo = BOrdering
TreeMap[B, Int]() // Now it works!
EDITAR : Esto solo está en Scala 2.8 (gracias, Ken)