2009-11-30 5 views
2

Je rencontre des problèmes pour étendre une classe de base étendue [Commandé] [Base]. Ma classe dérivée ne peut pas s'étendre Ordered [Derived] donc ne peut pas être utilisée comme une clé dans une TreeMap. Si je crée une TreeMap [Base], puis juste remplacer la comparaison dans Derived qui fonctionne, mais ce n'est pas ce que je veux. Je voudrais pouvoir avoir la classe dérivée comme clé. Y a-t-il un moyen de contourner ceci?Étendre la classe scala qui s'étend en ordre

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 
} 

Modifier

This discussion sur la liste de diffusion scala semble être très pertinent, mais il me perd un peu.

Répondre

4

Vous pouvez utiliser une conversion de type de B à Ordonné [B]:

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

Je pense que B doit toujours être un sous-type A qui implique ordre [A] de type A whoes est invariant. Il ne peut pas définir une seconde méthode de comparaison pour implémenter Order [B] avec le même type d'erreur que la méthode de comparaison de Ordered [A].

Vous pouvez également définir une version de type implicite de B à Ordonné [B]:

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

Cela devrait être valable. Je ne suis pas au courant d'un moyen d'exprimer cela dans le système de type sans moulage.

+0

Merci pour l'aide Thomas. J'espérais qu'il y aurait un peu de magie Scala que j'avais raté qui permettait à ça de fonctionner. Sans recourir essentiellement à un passage dans un comparateur. Est-ce que c'est juste moi ou cela semble-t-il très limitant, et assez ennuyeux? Ou est-ce juste à prévoir? – Dave

+0

Lorsque vous travaillez avec Ordered [T], vous êtes généralement supposé utiliser la relation <% pour demander que vous vouliez une vue qui commande l'objet. Si vous ne tapez pas, par exemple Int (qui n'élargit pas AnyRef, donc ils ne peuvent pas implémenter de traits), cela ne fonctionnera pas non plus avec votre conteneur. Notez que cette réponse ne concerne que Scala 2.7 –

+0

@Dave - J'ai ajouté une version de conversion de type implicite. Ce n'est pas parfait car une distribution est nécessaire. –

2

Vous pouvez mettre une commande implicite [B] portée quelque part, comme ceci:

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

EDIT: Ceci est seulement à Scala 2.8 (merci, Ken)

+1

Uniquement dans Scala 2.8 –

3

Le trait Ordered prend un paramètre. Un paramètre de type, accordé, mais il fonctionne comme n'importe quel autre paramètre. Lorsque vous l'étendez deux fois, dans la classe de base et dans la sous-classe, vous "n'importer" pas deux versions de Ordered. Au lieu de cela, la linéarisation des classes a lieu et vous ne l'importez qu'une seule fois. Pour cette raison, vous ne pouvez pas lui passer deux paramètres différents.

Maintenant, il y a une raison pour laquelle TreeMap ne nécessite pas de subclassOrdered, juste une conversion de votre classe à un Ordered de celui-ci. C'est précisément pour rendre de telles choses possibles. Au lieu d'étendre ces choses directement, vous devriez implicits pour eux:

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() 
+0

Comment gérez-vous les commandes naturelles pour A et B? Importer toujours AOrd._ & BOrd._ n'est pas sympa et chaque a1: A

+0

Comment produisez-vous ces jolies listes de sessions d'interprètes? – ziggystar

+0

L'interpréteur de scala: '$ scala'. –

Questions connexes