Как работает неявный порядок [Option [T]] в scala?

#scala #implicit

#scala #неявный

Вопрос:

Я немного поиграл с неявным разрешением и хотел понять, для чего полезен этот неявный val? При упорядочении мы имеем

 trait OptionOrdering[T] extends Ordering[Option[T]] {
    def optionOrdering: Ordering[T]
    def compare(x: Option[T], y: Option[T]) = (x, y) match {
      case (None, None)       => 0
      case (None, _)          => -1
      case (_, None)          => 1
      case (Some(x), Some(y)) => optionOrdering.compare(x, y)
    }
  }
  implicit def Option[T](implicit ord: Ordering[T]): Ordering[Option[T]] =
    new OptionOrdering[T] { val optionOrdering = ord }
  

Интересно, когда неявный параметр def[T] (неявный порядок: упорядочивание [T]): Упорядочивание[Option [T]] полезно или вызывается.

Я попробовал следующее:

 def test[Option[T]: Ordering](value1: Option[T], value2: Option[T]) = {
  val e = implicitly(Ordering[Option[T]]).compare(value1, value2)
}
  

Но компилятору это не нравится.

не найдено: type T def test[Опция [T]: Упорядочивание](значение 1: опция [T], значение 2: опция [T]) = {

и если я сделаю, что предоставлено, может не иметь смысла, но только ради

 def test[Option[Int]: Ordering](value1: Option[Int], value2: Option[Int]) = {
  val e = implicitly(Ordering[Option[Int]]).compare(value1, value2)
}

I get 

type Option takes type parameters
def test[Option[Int]: Ordering](value1: Option[Int], value2: Option[Int]) = {
No implicit Ordering defined for Option[Int]
  

Может кто-нибудь привести пример того, как использовать этот неявный и / или где он полезен и действительно используется?

Я предполагаю, что когда возникает необходимость в упорядочении [Option [T]], тогда эта функция вызывается для разрешения неявного. Но я не могу этого сделать….

РЕДАКТИРОВАТЬ Ну, я написал следующее, что имеет больше смысла

 def test(value1: Option[Int], value2: Option[Int]) = {
  val e = implicitly(Ordering[Option[Int]]).compare(value1, value2)
}
  

Тогда я не понимаю, связана ли проблема с контекстом с

 def test[Option[T]: Ordering](value1: Option[T], value2: Option[T]) = {
  val e = implicitly(Ordering[Option[T]]).compare(value1, value2)
}

What's wrong with writing a context bound like that ?
  

Комментарии:

1. Обратите внимание, что довольно странно иметь эту особенность, обычно вы просто реализуете анонимный класс в теле implicit def

Ответ №1:

Интересно, когда неявный параметр def[T] (неявный порядок: упорядочивание [T]): Упорядочивание[Option [T]] полезно или вызывается.

Неявные методы могут использоваться для создания экземпляров класса типа из других экземпляров класса типа, которые могут сохранять шаблон

 implicit def Option[T](implicit ord: Ordering[T]): Ordering[Option[T]] =
  new OptionOrdering[T] { val optionOrdering = ord }
  

Например, для данного экземпляра класса типа Ordering[Int] вышеупомянутый неявный метод может создавать экземпляр класса типа Ordering[Option[Int]] . (Не забудьте implicit параметр, иначе мы получим неявное преобразование, которое не одобряется).

что не так с [Option [T]: Упорядочивание]

Ключ в том, чтобы понять разницу между конструктором типа и правильным типом. Например, Option есть конструктор типов, который может создавать правильный тип Option[Int] . Предложение параметра типа [Option[T]: Ordering] в вашем определении

 def test[Option[T]: Ordering](value1: Option[T], value2: Option[T])
  

на самом деле не указывает Option конструктор типа. Просто так получилось, что вы назвали его так же, однако то, что вы указали, на самом деле больше похоже

 def test[F[T]: Ordering](value1: F[T], value2: F[T])
  

Кроме того, T in F[T] фактически не может использоваться в списке параметров метода, поэтому на самом деле ваше определение больше похоже на so

 def test[F[_]: Ordering](value1: F[T], value2: F[T])
  

Теперь ошибки должны быть понятнее; F[_]: Ordering требуется экземпляр класса типа, Ordering[F] где F является конструктором типа, однако таких экземпляров класса типа нет, потому что определение класса типа Ordering является

 trait Ordering[T]
  

где T — правильный тип. В противном случае это было бы определено примерно так

 trait Ordering[F[_]]
  

Примером такого класса типа является Functor

 trait Functor[F[_]]
  

Следовательно, чтобы синтаксически исправить ваше определение, попробуйте что-то вроде

 def test[T](value1: Option[T], value2: Option[T])(implicit ev: Ordering[Option[T]]) = {
  ev.compare(value1, value2)
}

test(Some(1), Some(42))
// res0: Int = -1

implicitly[Ordering[Option[Int]]].compare(Some(1), Some(42))
// res1: Int = -1
  

Здесь test(Some(1), Some(42)) эквивалентно

 test[Int](Some(1), Some(42))(Option[Int])
                                |
                         implicit method call
  

Комментарии:

1. Да, я согласен с ошибкой, я оставил ее для истории. Я получаю неявный, который вызывает неявный параметр. С этим проблем нет. Неявным разрешением может быть значение val или def, которые имеют только неявные параметры и возвращают нужный нам тип. Это нормально, однако, почему я не могу использовать контекстную привязку вместо явно неявного параметра, который вы сделали?

2. Я думаю, вопрос скорее в синтаксисе, связанном с контекстом, что не так с [Option[T]: Ordering] почему его нельзя перевести на implicit ev: Ordering[Option[T]] ?