Quel est l’identifiant Scala «implicitement»?

J’ai vu une fonction nommée implicitly utilisée dans les exemples Scala. Qu’est-ce que c’est et comment est-il utilisé?

Exemple ici :

 scala> sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo { | implicit def ssortingngImpl = new Foo[Ssortingng] { | def apply(list : List[Ssortingng]) = println("Ssortingng") | } | implicit def intImpl = new Foo[Int] { | def apply(list : List[Int]) = println("Int") | } | } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x) defined trait Foo defined module Foo foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit scala> foo(1) :8: error: type mismatch; found : Int(1) required: List[?] foo(1) ^ scala> foo(List(1,2,3)) Int scala> foo(List("a","b","c")) Ssortingng scala> foo(List(1.0)) :8: error: could not find implicit value for evidence parameter of type Foo[Double] foo(List(1.0)) ^ 

Notez que nous devons écrire implicitly[Foo[A]].apply(x) car le compilateur pense implicitly[Foo[A]](x) que implicitly[Foo[A]](x) signifie que nous appelons implicitly des parameters.

Voir aussi Comment étudier des objects / types / etc. de Scala REPL? et où Scala recherche-t-il les implicits?

Voici quelques raisons d’utiliser implicitly méthode délicieusement simple.

Pour comprendre / dépanner les vues implicites

Une vue implicite peut être déclenchée lorsque le préfixe d’une sélection (par exemple, the.prefix.selection(args) ne contient pas une selection membre applicable à args (même après avoir tenté de convertir des arguments avec des vues implicites). Dans ce cas, le compilateur recherche les membres implicites, définis localement dans les étendues actuelles ou englobantes, hérités ou importés, qui sont soit des fonctions du type que the.prefix vers un type avec une selection définie, soit des méthodes implicites équivalentes.

 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} =  scala> res22(1) // res23: AnyRef{def min(i: Int): Int} = 1 scala> .getClass res24: java.lang.Class[_] = class scala.runtime.RichInt 

Les vues implicites peuvent également être déclenchées lorsqu’une expression n’est pas conforme au type attendu, comme ci-dessous:

 scala> 1: scala.runtime.RichInt res25: scala.runtime.RichInt = 1 

Ici, le compilateur recherche cette fonction:

 scala> implicitly[Int => scala.runtime.RichInt] res26: (Int) => scala.runtime.RichInt =  

Accès à un paramètre implicite introduit par un contexte lié

Les parameters implicites sont sans doute une caractéristique plus importante de Scala que les vues implicites. Ils prennent en charge le modèle de classe de type. La bibliothèque standard utilise ceci dans quelques endroits – voir scala.Ordering et comment il est utilisé dans SeqLike#sorted . Les parameters implicites sont également utilisés pour transmettre des manifestes Array et des instances CanBuildFrom .

Scala 2.8 permet une syntaxe abrégée pour les parameters implicites, appelée Context Bounds. En bref, une méthode avec un paramètre de type A qui nécessite un paramètre implicite de type M[A] :

 def foo[A](implicit ma: M[A]) 

peut être réécrit comme suit:

 def foo[A: M] 

Mais à quoi ça sert de passer le paramètre implicite sans le nommer? Comment cela peut-il être utile lors de l’implémentation de la méthode foo ?

Souvent, le paramètre implicite ne doit pas nécessairement être référencé directement, il sera transposé sous la forme d’un argument implicite vers une autre méthode appelée. Si nécessaire, vous pouvez toujours conserver la signature de la méthode laconique avec la limite de contexte et appeler implicitly matérialisation de la valeur:

 def foo[A: M] = { val ma = implicitly[M[A]] } 

Passer explicitement un sous-ensemble de parameters implicites

Supposons que vous appelez une méthode qui imprime une personne, en utilisant une approche basée sur la classe de type:

 trait Show[T] { def show(t: T): Ssortingng } object Show { implicit def IntShow: Show[Int] = new Show[Int] { def show(i: Int) = i.toSsortingng } implicit def SsortingngShow: Show[Ssortingng] = new Show[Ssortingng] { def show(s: Ssortingng) = s } def ShoutySsortingngShow: Show[Ssortingng] = new Show[Ssortingng] { def show(s: Ssortingng) = s.toUpperCase } } case class Person(name: Ssortingng, age: Int) object Person { implicit def PersonShow(implicit si: Show[Int], ss: Show[Ssortingng]): 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) 

Que faire si nous voulons changer la façon dont le nom est sorti? Nous pouvons appeler explicitement PersonShow , passer explicitement une alternative Show[Ssortingng] , mais nous voulons que le compilateur réussisse le Show[Int] .

 Person.PersonShow(si = implicitly, ss = Show.ShoutySsortingngShow).show(p) 

Implicitly est disponible dans Scala 2.8 et est défini dans Predef comme:

 def implicitly[T](implicit e: T): T = e 

Il est couramment utilisé pour vérifier si une valeur implicite de type T est disponible et la retourner si tel est le cas.

Exemple simple de la présentation de retronym :

 scala> implicit val a = "test" // define an implicit value of type Ssortingng a: java.lang.Ssortingng = test scala> val b = implicitly[Ssortingng] // search for an implicit value of type Ssortingng and assign it to b b: Ssortingng = test scala> val c = implicitly[Int] // search for an implicit value of type Int and assign it to c :6: error: could not find implicit value for parameter e: Int val c = implicitly[Int] ^ 

Une réponse ” Apprendre à pêcher” consiste à utiliser l’index alphabétique des membres actuellement disponible dans les nightlies Scaladoc . Les lettres (et le # , pour les noms non alphabétiques) en haut du volet package / class sont des liens vers l’index des noms de membre commençant par cette lettre (dans toutes les classes). Si vous choisissez I , par exemple, vous trouverez l’entrée implicitly avec une occurrence, dans Predef , que vous pouvez visiter depuis le lien.