【问题标题】:Java SortedMap to Scala TreeMapJava SortedMap 到 Scala TreeMap
【发布时间】:2011-01-10 23:00:25
【问题描述】:

我在将 java SortedMap 转换为 scala TreeMap 时遇到问题。 SortedMap 来自反序列化,使用前需要转换成 scala 结构。

出于好奇,一些背景是序列化结构是通过 XStream 编写的,并且在反序列化时我注册了一个转换器,它说任何可以分配给 SortedMap[Comparable[_],_] 的东西都应该给我。因此,我的 convert 方法被调用并得到了一个 Object,我可以安全地转换它,因为我知道它的类型是 SortedMap[Comparable[_],_]。这就是有趣的地方。这里有一些示例代码可能有助于解释它。

// 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))  })

【问题讨论】:

  • (已编辑。)两个可比对象应该如何排序?我不太明白。键应该在 TreeMap 中排序。它们的键是 Comparable[]。因此,您需要订购 Comparables。所以你需要一个 Ordering[Comparable[]]。

标签: scala type-conversion scala-2.8


【解决方案1】:

首先,澄清你的错误:

// 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
//       ^

您可以编写一个隐式来将Comparable[T] 视为Ordering[T],如下所示。

// 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]]

但是,如果你真的不知道密钥的类型,我认为你不能按照Comparable#compareTo 创建Ordering,至少不用反射:

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)

【讨论】:

  • 我认为只要有可能,Ordering 比隐式转换为 Ordered 更可取。排序或其他顺序敏感算法需要的每次比较都会调用后者。
  • 谢谢retronym。不幸的是,我不知道类型,这使它成为一个有点混乱的问题。不过,您编写的代码效果很好。
【解决方案2】:

您也可以只为 TreeMap 提供显式类型。这就是我刚刚解决了一个类似问题的方法:

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

(抱歉,我没有时间检查这究竟如何适用于问题中发布的来源。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-08
    • 2019-08-27
    • 2013-12-30
    • 1970-01-01
    相关资源
    最近更新 更多