Это один из самых испорченных примеров, которые я когда-либо видел, что может пойти не так, когда вы врете компилятору! : -)
Я покажу, что происходит построчно, чтобы можно было видеть, что происходит (но 0__ верно и заслуживает принятого ответа).
val e:Heap[Int] = Heap.empty[Int]
Это звонит
def empty[E] = emptyEl.asInstanceOf[Heap[E]]
Какие звонки
private val emptyEl = new Nil[Nothing]
Что подразумевается под Ordering[Nothing]
. Я был очень удивлен, что такое произошло, поэтому я посмотрел его. Одна вещь о Ordering
заключается в том, что если ваша коллекция Ordered
, она сделает доступной Ordering
. Метод, который обеспечивает это:
implicit def ordered [A <: Ordered[A]]: Ordering[A] = new Ordering[A] {
def compare(x: A, y: A) = x.compare(y)
}
Итак, вот сделка о Nothing
: это подкласс всего. Ergo, это подкласс Ordered[Nothing]
, поэтому доступно Ordering[Nothing]
.
Во всяком случае, пока нет ошибок. Следующая строка:
val e1:Heap[Int] = e insert 3
Звонит insert
на Nil
:
def insert(e: E):Heap[E] = Node[E](e,Heap.empty,Heap.empty,1)
Обратите внимание, что Ordering[E]
не передается методу insert
, поэтому он использует тот, который передан Nil
, Ordering[Nothing]
. Все еще без ошибок, поэтому следующая строка:
val e2:Heap[Int] = e1 insert 5
Это звонит insert
на Node
:
def insert(e: E):Heap[E] = Node(e,empty,empty,1).merge(this)
Опять же, Ordering[E]
не было передано, поэтому он использует тот, который он получил при создании, все еще Ordering[Nothing]
. Это в конечном итоге приведет к ошибке, в этой строке merge
:
case (Node(x,l1,r1,_),Node(y,l2,r2,_)) => if (x < y) makeT(x,l1,r1.merge(h)) else makeT(y,l2,this.merge(r2))
Выражение x < y
является проблемой. В x
не определен метод <
, поскольку x
- это просто обобщенный E
, поэтому он выполняет неявное преобразование для его выполнения:
new ordering.Ops(x) < y
Где Ops.<
:
def <(rhs: T) = lt(lhs, rhs)
И lt
определяется на ordering
(который был импортирован). Другими словами, он выполняет это:
ordering.lt(x, y)
Это приведет к вызову ordering.compare
. Ранее мы видели определение для Ordering[Nothing]
, которое было:
x.compare(y)
И вот где происходит ошибка. Тип x
- java.lang.Integer
(из-за автобокса). Метод compare
взят из scala.math.Ordered
, который java.lang.Integer
явно не реализует.
Так что не получается. Все это из-за маленькой белой лжи ...: -)
Если, с другой стороны, используется Ordering[Int]
, он прибегнет к этому определению:
def compare(x: Int, y: Int) =
if (x < y) -1
else if (x == y) 0
else 1
}
Здесь <
существует, потому что x
есть Int
.