Вот несколько причин использовать восхитительно простой метод implicitly
.
Чтобы понять / устранить неполадки неявных представлений
Неявное представление может быть запущено, когда префикс выбора (например, the.prefix.selection(args)
не содержит члена, selection
который применим к args
(даже после попытки преобразования args
с неявными представлениями). В этом случае компилятор ищет неявные члены, локально определенные в текущей или вложенной области видимости, наследуемой или импортированной, которые являются либо функциями от типа этого the.prefix
к типу с selection
определенными, либо эквивалентными неявными методами.
scala> 1.min(2) // Int doesn't have min defined, where did that come from?
res21: Int = 1
scala> implicitly[Int => { def min(i: Int): Any }]
res22: (Int) => AnyRef{def min(i: Int): Any} = <function1>
scala> res22(1) //
res23: AnyRef{def min(i: Int): Int} = 1
scala> .getClass
res24: java.lang.Class[_] = class scala.runtime.RichInt
Неявные представления также могут запускаться, когда выражение не соответствует ожидаемому типу, как показано ниже:
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1
Здесь компилятор ищет эту функцию:
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
Доступ к неявному параметру, введенному ограниченным контекстом
Неявные параметры, возможно, являются более важной особенностью Scala, чем неявные представления. Они поддерживают шаблон класса типа. Стандартная библиотека использует это в нескольких местах - см.scala.Ordering
и как это используется SeqLike#sorted
. Неявные параметры также используются для передачи манифестов и CanBuildFrom
экземпляров массива .
Scala 2.8 допускает сокращенный синтаксис для неявных параметров, называемый контекстными границами. Вкратце, метод с параметром типа, A
который требует неявного параметра типа M[A]
:
def foo[A](implicit ma: M[A])
можно переписать как:
def foo[A: M]
Но какой смысл передавать неявный параметр, а не называть его? Как это может быть полезно при реализации методаfoo
?
Часто на неявный параметр не нужно ссылаться напрямую, он будет туннелироваться как неявный аргумент для другого вызываемого метода. Если это необходимо, вы все равно можете сохранить краткую подпись метода с привязкой к контексту и вызвать implicitly
для материализации значения:
def foo[A: M] = {
val ma = implicitly[M[A]]
}
Передача подмножества неявных параметров в явном виде
Предположим, вы вызываете метод, который довольно печатает человека, используя подход на основе классов типов:
trait Show[T] { def show(t: T): String }
object Show {
implicit def IntShow: Show[Int] = new Show[Int] { def show(i: Int) = i.toString }
implicit def StringShow: Show[String] = new Show[String] { def show(s: String) = s }
def ShoutyStringShow: Show[String] = new Show[String] { def show(s: String) = s.toUpperCase }
}
case class Person(name: String, age: Int)
object Person {
implicit def PersonShow(implicit si: Show[Int], ss: Show[String]): Show[Person] = new Show[Person] {
def show(p: Person) = "Person(name=" + ss.show(p.name) + ", age=" + si.show(p.age) + ")"
}
}
val p = Person("bob", 25)
implicitly[Show[Person]].show(p)
Что если мы хотим изменить способ вывода имени? Мы можем явно вызвать PersonShow
, явно передать альтернативу Show[String]
, но мы хотим, чтобы компилятор передал Show[Int]
.
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)
Implicitly
доступна в Scala 2.8 и определяется в Predef как:Обычно используется для проверки доступности неявного значения типа
T
и его возврата если это так.Простой пример из презентации ретронима :
источник
implicitly[Ordering[(Int, String)]].compare( (1, "b"), (1, "a") )
особенно для извлечения неявного параметра, введенного ограничением контекста:def foo[A: Ordering](a1: A, a2: A) = implicitly[Ordering[A]].compare(a1, a2)
Ответ «научить вас ловить рыбу» заключается в использовании алфавитного индекса, доступного в настоящее время в ночных еженедельниках Скаладока . Буквы (и
#
, для неалфавитных имен) в верхней части панели пакета / класса являются ссылками на индекс для имен членов, начинающихся с этой буквы (для всех классов). Если вы выберетеI
, например, вы найдетеimplicitly
запись с одним вхождением, вPredef
которой вы можете перейти по ссылке там.источник
implicit
кажется важной языковой особенностью в Scala и, безусловно, заслуживает правильного объяснения. Думать, что документы, в которых указывается только количество подписей типов, больше похоже на интеллектуальное самоудовлетворение, чем на подлинный ответ. Посмотрите конкретные вопросы, заданные ОП - что это такое и как оно используется? Ни на этот вопрос, ни в ночных документах, на которые вы даже не предоставили фактическую ссылку. scala-lang.org/files/archive/nightly/docs/library/… Это ничему не учит. См. Niklaus Wirth или Turbo Pascal для примеров подлинных документов. -1implicit
иimplicitly
связаны, но довольно отчетливо.implicit
Ключевым словом является частью языка.implicitly
определяется в виде простого кода Scala в стандартной библиотеке. Поскольку он-лайн документы содержат ссылки на источники, я считаю, что все же лучше направлять вопросы к этим документам и связанному источнику.