2010-01-29 2 views
3

J'ai des problèmes pour convertir une SortedMap java en une scala TreeMap. Le SortedMap vient de la désérialisation et doit être converti en une structure de scala avant d'être utilisé. Un peu de contexte, pour les curieux, est que la structure sérialisée est écrite à travers XStream et lors de la désialisation, j'enregistre un convertisseur qui dit que tout ce qui peut être assigné à SortedMap[Comparable[_],_] devrait me être donné. Donc, ma méthode convert est appelée et reçoit un Object que je peux lancer en toute sécurité car je sais que c'est de type SortedMap[Comparable[_],_]. C'est là que ça devient intéressant. Voici un exemple de code qui pourrait vous aider à l'expliquer.Java SortedMap to Scala TreeMap

// a conversion from comparable to ordering 
scala> implicit def comparable2ordering[A <: Comparable[A]](x: A): Ordering[A] = new Ordering[A] { 
    |  def compare(x: A, y: A) = x.compareTo(y) 
    | } 
comparable2ordering: [A <: java.lang.Comparable[A]](x: A)Ordering[A] 

// jm is how I see the map in the converter. Just as an object. I know the key 
// is of type Comparable[_] 
scala> val jm : Object = new java.util.TreeMap[Comparable[_], String]()   
jm: java.lang.Object = {} 

// It's safe to cast as the converter only gets called for SortedMap[Comparable[_],_] 
scala> val b = jm.asInstanceOf[java.util.SortedMap[Comparable[_],_]] 
b: java.util.SortedMap[java.lang.Comparable[_], _] = {} 

// Now I want to convert this to a tree map 
scala> collection.immutable.TreeMap() ++ (for(k <- b.keySet) yield { (k, b.get(k)) }) 
<console>:15: error: diverging implicit expansion for type Ordering[A] 
starting with method Tuple9 in object Ordering 
     collection.immutable.TreeMap() ++ (for(k <- b.keySet) yield { (k, b.get(k)) }) 
+0

Comment sont deux comparables supposés se mettre en ordre? Je ne comprends pas très bien. Les clés sont censées être commandées dans une TreeMap. Les clés sont comparables [_]. Donc, vous devez commander des comparables. Vous avez donc besoin d'une commande [Comparable [_]]. –

Répondre

2

Tout d'abord, pour clarifier votre erreur:

// The type inferencer can't guess what you mean, you need to provide type arguments. 
// new collection.immutable.TreeMap 
// <console>:8: error: diverging implicit expansion for type Ordering[A] 
//starting with method Tuple9 in object Ordering 
//  new collection.immutable.TreeMap 
//  ^

Vous pouvez écrire un implicite pour traiter Comparable[T] comme Ordering[T] comme suit.

// This implicit only needs the type parameter. 
implicit def comparable2ordering[A <: Comparable[A]]: Ordering[A] = new Ordering[A] { 
    def compare(x: A, y: A) = x.compareTo(y) 
} 

trait T extends Comparable[T] 

implicitly[Ordering[T]] 

Cependant, si vous ne savez vraiment pas le type de la clé, je ne pense pas que vous pouvez créer le Ordering en termes de Comparable#compareTo, au moins sans réflexion:

val comparableOrdering = new Ordering[AnyRef] { 
    def compare(a: AnyRef, b: AnyRef) = { 
    val m = classOf[Comparable[_]].getMethod("compareTo", classOf[Object]) 
    m.invoke(a, b).asInstanceOf[Int] 
    } 
} 
new collection.immutable.TreeMap[AnyRef, AnyRef]()(comparableOrdering) 
+0

Je pense que, dans la mesure du possible, un Ordre est préférable à une conversion implicite en Ordre. Ce dernier sera appelé pour chaque comparaison dont le tri ou un autre algorithme sensible aux ordres a besoin. –

+0

Merci Retronyme. Malheureusement, je ne connais pas le type, ce qui en fait un problème un peu salissant. Le code que vous avez écrit fonctionne très bien. – Dave

0

Vous peut probablement aussi donner un type explicite à la TreeMap. Voilà comment je viens de résoudre un problème similaire: (. Edité)

collection.immutable.TreeMap[whatever,whatever]() ++ ... 

(. Désolé, je n'ai pas le temps de vérifier exactement comment cela s'applique aux sources affichées dans la question)