Aqui estão algumas razões para usar o método deliciosamente simples implicitly.
Para entender / solucionar problemas de vistas implícitas
Uma visualização implícita pode ser acionada quando o prefixo de uma seleção (considere, por exemplo, the.prefix.selection(args)não contém um membro selectionaplicável a ele args(mesmo depois de tentar converter argscom as visualizações implícitas) .Neste caso, o compilador procura por membros implícitos, definidos localmente nos escopos atuais ou anexos, herdados ou importados, que são Funções do tipo the.prefixpara um tipo com selectionmétodos implícitos definidos ou equivalentes.
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
As vistas implícitas também podem ser acionadas quando uma expressão não está em conformidade com o tipo esperado, como abaixo:
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1
Aqui o compilador procura esta função:
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
Acessando um parâmetro implícito introduzido por um limite de contexto
Parâmetros implícitos são indiscutivelmente um recurso mais importante do Scala que as visualizações implícitas. Eles suportam o padrão de classe de tipo. A biblioteca padrão usa isso em alguns lugares - veja scala.Orderinge como é usado SeqLike#sorted. Parâmetros implícitos também são usados para transmitir manifestos e CanBuildFrominstâncias de matriz .
O Scala 2.8 permite uma sintaxe abreviada para parâmetros implícitos, chamados limites de contexto. Resumidamente, um método com um parâmetro de tipo Aque requer um parâmetro implícito do tipo M[A]:
def foo[A](implicit ma: M[A])
pode ser reescrito como:
def foo[A: M]
Mas qual é o sentido de passar o parâmetro implícito, mas não de nomeá-lo? Como isso pode ser útil ao implementar o método foo?
Freqüentemente, o parâmetro implícito não precisa ser referido diretamente, ele será encaminhado como um argumento implícito para outro método chamado. Se for necessário, você ainda pode manter a assinatura do método conciso com o Limite de Contexto e chamar implicitlypara materializar o valor:
def foo[A: M] = {
val ma = implicitly[M[A]]
}
Passando um subconjunto de parâmetros implícitos explicitamente
Suponha que você esteja chamando um método que imprima bastante uma pessoa, usando uma abordagem baseada em classe de tipo:
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)
E se quisermos mudar a maneira como o nome é exibido? Podemos chamar explicitamente PersonShow, passar explicitamente uma alternativa Show[String], mas queremos que o compilador passe a Show[Int].
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)