Вы выбрали крепкий орешек для новичка в Scala! : -)
Хорошо, краткий тур, не ожидайте, что полностью поймете это прямо сейчас. Во-первых, обратите внимание, что проблема возникает по методу ++
. В поисках его определения мы находим его по признаку MapLike
, получая либо Iterator
, либо Traversable
. Поскольку y
является SortedMap
, то используется версия Traversable
.
Обратите внимание, что в расширенной сигнатуре типа передается CanBuildFrom
. Он передается неявно, поэтому вам не нужно беспокоиться об этом. Однако, чтобы понять, что происходит, на этот раз вы делаете.
Вы можете найти CanBuildFrom, щелкнув по нему там, где он указан в определении ++
, или с помощью фильтрации. Как упомянул Рэндалл в комментариях, в левом верхнем углу скалярной страницы есть не отмеченное пустое поле. Вам просто нужно нажать там и ввести текст, и он вернет совпадения для того, что вы ввели.
Итак, найдите черту CanBuildFrom
в ScalaDoc и выберите ее. Он имеет большое количество подклассов, каждый из которых отвечает за создание определенного типа коллекции. Найдите и выберите подкласс SortedMapCanBuildFrom
. Это класс объекта, который вам нужен для получения SortedMap
из Traversable
. Обратите внимание на конструктор экземпляра (конструктор для класса), который получает неявный параметр Ordering
. Теперь мы приближаемся.
На этот раз используйте фильтр фильтра для поиска Ordering
. В его сопутствующем объекте (нажмите на маленькое «o» имя) размещается неявное выражение, которое будет генерировать Ordering
s, так как сопутствующие объекты проверяются на наличие последствий, генерирующих экземпляры или преобразования для этого класса. Внутри признака LowPriorityOrderingImplicits
определяется, какой объект Ordering
расширяется, и, глядя на него, вы увидите метод ordered[A <: Ordered[A]]
, который будет производить Ordering
, необходимый ... или будет производить его, если только там не было проблемой.
Можно предположить, что неявного преобразования из X
в Ordered[X]
будет достаточно, так же, как я это делал до того, как более внимательно изучить это. Это, однако, является преобразованием объектов , и ordered
ожидает получения типа , который является подтипом Ordered[X]
. Хотя можно преобразовать объект типа X
в объект типа Ordered[X]
, X
сам по себе не является подтипом Ordered[X]
, поэтому его нельзя передать в качестве параметра в ordered
.
С другой стороны, вы можете создать неявное val
Ordering[X]
вместо def
Ordered[X]
, и вы справитесь с проблемой. В частности:
object ViewBoundExample {
class X
def combine[Y](a: SortedMap[X, Y], b: SortedMap[X, Y]): SortedMap[X, Y] = {
a ++ b
}
implicit val orderingX = new Ordering[X] { def compare(x: X, y: X) = 0 }
}
Я думаю, что у большинства людей первоначальная реакция на Ordered
/ Ordering
должна быть одной из недоумений: почему занятия для одной и той же вещи? Первый расширяет java.lang.Comparable
, а второй расширяет java.util.Comparator
. Увы, подпись типа для compare
в основном суммирует основное различие:
def compare(that: A): Int // Ordered
def compare(x: T, y: T): Int // Ordering
Использование Ordered[A]
требует либо A
для расширения Ordered[A]
, что потребует от него изменения определения A
или передачи метода который может конвертировать A
в Ordered[A]
. Scala вполне может выполнить последнее легко, но тогда у вас есть для преобразования каждого экземпляра перед сравнением.
С другой стороны, использование Ordering[A]
требует создания одного объекта, как показано выше. Когда вы используете его, вы просто передаете два объекта типа A
в compare
- никакие объекты не создаются в процессе.
Таким образом, есть некоторый прирост производительности, но есть гораздо более важная причина для предпочтения Scala Ordering
, а не Ordered
. Посмотрите еще раз на объект-компаньон Ordering
. Вы заметите, что для многих классов Scala, определенных там, есть несколько последствий. Вы можете вспомнить, как я упоминал ранее, что неявный для класса T
будет искать внутри объекта-компаньона T
, и это именно то, что происходит.
Это можно сделать и для Ordered
. Однако, и это является камнем преткновения, это означает, что любой метод, поддерживающий как Ordering
, так и Ordered
, потерпит неудачу! Это потому, что Scala будет искать неявное, чтобы заставить его работать, и найдет два: один для Ordering
, один для Ordered
. Будучи не в состоянии решить, что именно вы хотели, Scala отказывается с сообщением об ошибке. Итак, выбор должен был быть сделан, и у Ordering
было больше возможностей для этого.
Дух, я забыл объяснить, почему подпись не определяется как ordered[A <% Ordered[A]]
вместо ordered[A <: Ordered[A]]
. Я подозреваю, что из-за этого возникнет ошибка с двойной импликацией, о которой я упоминал ранее, но я спрошу парня, который действительно сделал эту вещь и имел двойные неявные проблемы, проблематичен ли этот конкретный метод.