隐式转换导致堆栈溢出

3
以下代码片段之前完美运行,然后在不同文件中进行了一些代码更改后,我开始出现堆栈溢出,导致隐式转换递归调用。这种情况发生过吗?如果有,有什么解决方法。
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)
  }
} 

一些注释,虽然我不是完全确定。难道不是 A <: Comparable[A] 吗?在匿名类中调用 compareTo 时,您不需要绑定 x,对吧? - Dario
DateTime 作为原始类型实现了 Comparable 接口,因此 Comparable[A] 编译不通过。 - user44242
只需将Comparable[_]替换为Ordered[DateTime]并将compareTo重命名为compare,因为OrderedComparable的子类,所以兼容性相当好。 - soc
@user44242 - 你第一次提到DateTime是在这条评论中。你应该更明确地修改你的问题,因为它对你的问题非常核心。 - oxbow_lakes
1个回答

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)

当然,你还需要将Ordering隐式转换为Ordered才能利用scala的比较运算符<>=等:

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
}

我的类型是DateTime,它作为原始类型实现了Comparable接口,在这种情况下,你建议的会编译失败。 - user44242
@user44242 - 那么也许你应该在问题中加入那一部分? - oxbow_lakes
我已经更新了我的回答;我认为你需要为你的 DateTime 类型提供一个明确的转换。 - oxbow_lakes
1
以后参考,你可以通过引入 scala.math.Ordered.orderingToOrdered 从 Comparable[A] 跳转到 Ordered[A],因为上面的解决方案已经存在于 Scala 库中。 - Jon Freedman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接