Hier sind einige Gründe, die wunderbar einfache Methode anzuwenden implicitly
.
Implizite Ansichten verstehen / Fehler beheben
Eine implizite Ansicht kann ausgelöst werden, wenn das Präfix einer Auswahl (z. B. the.prefix.selection(args)
enthält es kein Element selection
, auf das es anwendbar ist args
(auch nach dem Versuch, args
mit impliziten Ansichten zu konvertieren ). In diesem Fall sucht der Compiler nach impliziten Elementen, die lokal definiert sind In den aktuellen oder umschließenden Bereichen, geerbt oder importiert, handelt es sich entweder um Funktionen vom Typ dieses the.prefix
Typs zu einem Typ mit selection
definierten oder äquivalenten impliziten Methoden.
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
Implizite Ansichten können auch ausgelöst werden, wenn ein Ausdruck nicht dem erwarteten Typ entspricht (siehe unten):
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1
Hier sucht der Compiler nach dieser Funktion:
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
Zugriff auf einen impliziten Parameter, der durch eine Kontextbindung eingeführt wird
Implizite Parameter sind wohl ein wichtigeres Merkmal von Scala als implizite Ansichten. Sie unterstützen das Typklassenmuster. Die Standardbibliothek verwendet dies an einigen Stellen - sehen Sie, scala.Ordering
wie es verwendet wird SeqLike#sorted
. Implizite Parameter werden auch zum Übergeben von Array-Manifesten und CanBuildFrom
-Instanzen verwendet.
Scala 2.8 ermöglicht eine Kurzsyntax für implizite Parameter, die als Kontextgrenzen bezeichnet wird. Kurz gesagt, eine Methode mit einem Typparameter A
, für den ein impliziter Parameter vom Typ erforderlich ist M[A]
:
def foo[A](implicit ma: M[A])
kann umgeschrieben werden als:
def foo[A: M]
Aber was bringt es, den impliziten Parameter zu übergeben, aber nicht zu benennen? Wie kann dies bei der Implementierung der Methode hilfreich sein foo
?
Oft muss auf den impliziten Parameter nicht direkt verwiesen werden, sondern er wird als implizites Argument zu einer anderen aufgerufenen Methode getunnelt. Wenn es benötigt wird, können Sie die knappe Methodensignatur mit dem Context Bound beibehalten und aufrufen, implicitly
um den Wert zu materialisieren:
def foo[A: M] = {
val ma = implicitly[M[A]]
}
Eine Teilmenge impliziter Parameter explizit übergeben
Angenommen, Sie rufen eine Methode auf, die eine Person mit einem typklassenbasierten Ansatz hübsch druckt:
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)
Was ist, wenn wir die Art und Weise ändern möchten, in der der Name ausgegeben wird? Wir können explizit PersonShow
eine Alternative aufrufen , explizit übergeben Show[String]
, aber wir möchten, dass der Compiler die übergibt Show[Int]
.
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)