В чем преимущество Scala с привязкой к контексту над обычным параметром?
Я читаю о границах контекста и неявных параметрах, которые должны работать как классы типов. Примеры, которые я часто вижу Ordering[T]
, Что-то вроде:
foo[T : Ordering](a: T, b: T)
который является сахаром для
foo[T](a: T, b: T)(implicit ord: Ordering[T])
так что в теле можно сделать что-то вроде
ord.compare(a, b)
Я думал, что понял это раньше, и теперь я рисую пробел... в чем преимущество перед простой передачей вещи в функцию. Например:
foo[T](a: T, b: T, ord: Ordering[T])
/* or */ foo[T](a: T, b: T)(ord: Ordering[T])
foo(a, b, myOrdering)
/* or */ foo(a, b)(myOrdering)
1 ответ
Я постараюсь ответить подробно ниже. Краткий ответ: не нужно явно передавать неявные значения неявным параметрам другого метода.
Как я понимаю, вы не против синтаксического сахара границ контекста, и вы это понимаете, поэтому я просто пропущу эту часть.
Представьте, что у вас есть два метода сортировки: один сортирует весь массив, другой сортирует только его часть. Они имеют следующие подписи:
sort[T](as: Array[T], ord: Ordering[T]): Unit = sort(as, 0, as.length, ord)
sort[T](as: Array[T], from: Int, to: Int, ord: Ordering[T]): Unit = ???
Теперь, если было неявное значение Ordering и были неявные параметры, подобные этому:
sort[T](as: Array[T])(implicit ord: Ordering[T]): Unit = sort(as, 0, as.length/*)( ord*/)
sort[T](as: Array[T], from: Int, to: Int)(implicit ord: Ordering[T]): Unit = ???
или с границами контекста:
sort[T:Ordering](as: Array[T]): Unit = sort(as, 0, as.length/*)( ord*/)
sort[T:Ordering](as: Array[T], from: Int, to: Int): Unit = ???
Видите, нам не нужно было указывать порядок для общего случая. Вы можете представить это с более глубокой передачей параметра. В этом случае использование проще, хотя объявление без привязки к контексту немного более утомительно.
(Для полноты получения экземпляра с привязкой к контексту: implicitly[Ordering[T]]
где-то в ???
реализация.)