Aquí hay algunas razones para usar el método deliciosamente simple implicitly
.
Para comprender / solucionar problemas de vistas implícitas
Una vista implícita se puede activar cuando el prefijo de una selección (considere, por ejemplo, the.prefix.selection(args)
no contiene un miembro selection
que sea aplicable args
(incluso después de intentar convertir args
con vistas implícitas). En este caso, el compilador busca miembros implícitos, definidos localmente en los ámbitos actuales o delimitadores, heredados o importados, que son funciones desde el tipo de ese the.prefix
tipo hasta un tipo con selection
métodos implícitos definidos o 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
Las Vistas implícitas también se pueden activar cuando una expresión no se ajusta al Tipo esperado, como se muestra a continuación:
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1
Aquí el compilador busca esta función:
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
Acceso a un parámetro implícito introducido por un contexto limitado
Los parámetros implícitos son posiblemente una característica más importante de Scala que las Vistas implícitas. Soportan el patrón de clase de tipo. La biblioteca estándar usa esto en algunos lugares: vea scala.Ordering
y cómo se usa SeqLike#sorted
. Los parámetros implícitos también se utilizan para pasar manifiestos de matriz e CanBuildFrom
instancias.
Scala 2.8 permite una sintaxis abreviada para parámetros implícitos, llamados límites de contexto. Brevemente, un método con un parámetro de tipo A
que requiere un parámetro implícito de tipo M[A]
:
def foo[A](implicit ma: M[A])
puede reescribirse como:
def foo[A: M]
Pero, ¿qué sentido tiene pasar el parámetro implícito pero no nombrarlo? ¿Cómo puede ser útil esto al implementar el método foo
?
A menudo, no es necesario hacer referencia directa al parámetro implícito, se canalizará como un argumento implícito a otro método que se llama. Si es necesario, aún puede conservar la firma del método con el Context Bound y llamar implicitly
para materializar el valor:
def foo[A: M] = {
val ma = implicitly[M[A]]
}
Pasar un subconjunto de parámetros implícitos explícitamente
Supongamos que está llamando a un método que imprime bastante a una persona, utilizando un enfoque basado en clases 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)
¿Qué sucede si queremos cambiar la forma en que se genera el nombre? Podemos llamar explícitamente PersonShow
, pasar explícitamente una alternativa Show[String]
, pero queremos que el compilador pase la Show[Int]
.
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)