隐式转换会导致堆栈溢出

时间:2011-01-16 13:13:00

标签: scala

以下代码片段工作正常,然后在不同文件中的一些代码更改后,我开始获得由于隐式转换的递归调用而导致的堆栈溢出。这是不是发生在任何人身上,如果有的话,那是什么问题。

implicit def comparable2ordered[A <: Comparable[_]](x: A): Ordered[A] =
new Ordered[A] with Proxy {
  val self = x

  def compare(y: A): Int = {
    self.compareTo(y)
  }
} 

1 个答案:

答案 0 :(得分:4)

首先,我认为堆栈溢出的原因是使用[A <: Comparable[_]]存在类型在实践中意味着您无法将A与任何内容进行比较。这意味着编译器正在“选择”隐式转换以在self.compareTo调用中重新调用(因此递归)。如果您使用编译器开关 -XprintTypes

,您会看到这一点

那该怎么办?


考虑OrderingOrdered之间的差异。您的类型应该有隐式排序。

implicit def comp2ord[A <: Comparable[A]] = new Ordering[A] {
  def compare(x : A, y : A) = x compareTo y
}

然后将这种排序转换为Ordered

implicit def ordering2order[A : Ordering](x : A) = new Ordered[A] {
  def compare(y : A) = implicitly[Ordering[A]].compare(x, y)
}

没有隐式排序的用法:

scala> val df = new java.text.SimpleDateFormat("yyyy-MM-dd")
df: java.text.SimpleDateFormat = java.text.SimpleDateFormat@f67a0200

scala> TreeSet(df.parse("2011-03-04"), df.parse("2010-05-06"))
<console>:13: error: could not find implicit value for parameter ord: Ordering[java.util.Date]
   TreeSet(df.parse("2011-03-04"), df.parse("2010-05-06"))
          ^

现在有一个隐含的排序......

scala> implicit def comp2ord[A <: Comparable[A]] = new Ordering[A] {
 | def compare(x : A, y : A) = x compareTo y
 | }
comp2ord: [A <: java.lang.Comparable[A]]java.lang.Object with Ordering[A]

scala> TreeSet(df.parse("2011-03-04"), df.parse("2010-05-06"))
res1: scala.collection.immutable.TreeSet[java.util.Date] = TreeSet(Fri Mar 04 00:00:00 GMT 2011, Thu May 06 00:00:00 BST 2010)

当然,您还需要OrderingOrdered的隐式转换,以便通过<>=来利用scala的比较{1}}等:

scala> implicit def ordering2order[A : Ordering](x : A) = new Ordered[A] {
 | def compare(y : A) = implicitly[Ordering[A]].compare(x, y)
 | }
ordering2order: [A](a: A)(implicit evidence$1: Ordering[A])java.lang.Object with Ordered[A]

scala> df.parse("2010-04-05") < df.parse("2009-01-01")
res2: Boolean = false

如果您的类型A是实现原型 Comparable的Java类,则必须提供显式转换:

implicit def comp2ord(x : DateTime) = new Ordered[DateTime] {
  def compare(y : DateTime) = x compareTo y
}