Неявное преобразование вызывает переполнение стека - PullRequest
3 голосов
/ 16 января 2011

Следующий фрагмент кода работал отлично, затем, после некоторых изменений кода в разных файлах, я начал получать переполнения стека в результате рекурсивного вызова неявного преобразования.Случалось ли это когда-либо с кем-то, и если да, то в чем же дело.

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 Ответ

4 голосов
/ 16 января 2011

Во-первых, я думаю, что причиной переполнения вашего стека является использование [A <: Comparable[_]].Экзистенциальный тип на практике означает, что на самом деле вы не можете сравнить A ни с чем.Это означает, что компилятор «выбирает» неявное преобразование для повторного вызова в вызове self.compareTo (отсюда и рекурсия).Вы бы увидели это, если бы использовали переключатель компилятора -XprintTypes

Так что же делать?

Рассмотрим разницу между Ordering и Ordered.Должен быть неявный порядок для вашего типа.

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 является классом Java, который реализует raw-type Comparable, вам нужно будет предоставить явное преобразование:

implicit def comp2ord(x : DateTime) = new Ordered[DateTime] {
  def compare(y : DateTime) = x compareTo y
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...