Ich machte mich auf den Weg durch das Scala Playframework-Tutorial und stieß auf diesen Codeausschnitt, der mich verwirrt hatte:
def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Task.all(), errors)),
label => {
Task.create(label)
Redirect(routes.Application.tasks())
}
)
}
Also entschied ich mich zu untersuchen und stieß auf diesen Beitrag .
Ich verstehe es immer noch nicht.
Was ist der Unterschied zwischen diesen:
implicit def double2Int(d : Double) : Int = d.toInt
und
def double2IntNonImplicit(d : Double) : Int = d.toInt
abgesehen von der offensichtlichen Tatsache, dass sie unterschiedliche Methodennamen haben.
Wann soll ich verwenden implicit
und warum?
scala
syntax
playframework
keyword
Clive
quelle
quelle
Antworten:
Ich werde die Hauptanwendungsfälle von Implikits unten erklären, aber für weitere Details siehe das relevante Kapitel der Programmierung in Scala .
Implizite Parameter
Die endgültige Parameterliste einer Methode kann markiert werden. Dies
implicit
bedeutet, dass die Werte aus dem Kontext entnommen werden, in dem sie aufgerufen werden. Wenn der Gültigkeitsbereich keinen impliziten Wert des richtigen Typs enthält, wird er nicht kompiliert. Da der implizite Wert in einen einzelnen Wert aufgelöst werden muss und um Konflikte zu vermeiden, ist es eine gute Idee, den Typ für seinen Zweck spezifisch zu machen, z. B. erfordern Sie nicht, dass Ihre Methoden einen impliziten Wert findenInt
!Beispiel:
Implizite Konvertierungen
Wenn der Compiler einen Ausdruck des falschen Typs für den Kontext findet, sucht er nach einem impliziten
Function
Wert eines Typs, der eine Typprüfung ermöglicht. WennA
also a erforderlich ist und a findetB
, sucht esB => A
im Gültigkeitsbereich nach einem impliziten Wert vom Typ type (überprüft auch einige andere Stellen wie in denB
undA
Companion-Objekten, falls vorhanden). Dadef
s zuFunction
Objekten "eta-erweitert" werden kann, ist dies auch einimplicit def xyz(arg: B): A
Wille.Der Unterschied zwischen Ihren Methoden besteht also darin, dass die markierte Methode
implicit
vom Compiler für Sie eingefügt wird, wenn eineDouble
gefunden wird, aber eineInt
erforderlich ist.wird genauso funktionieren wie
Im zweiten haben wir die Konvertierung manuell eingefügt. Im ersten Fall hat der Compiler dasselbe automatisch getan. Die Konvertierung ist aufgrund der Typanmerkung auf der linken Seite erforderlich.
In Bezug auf Ihren ersten Ausschnitt aus Play:
Aktionen werden auf dieser Seite in der Play-Dokumentation erläutert (siehe auch API-Dokumente ). Du benutzt
auf dem
Action
Objekt (das der Begleiter des gleichnamigen Merkmals ist).Wir müssen also eine Funktion als Argument angeben, die als Literal in der Form geschrieben werden kann
In einem Funktionsliteral ist der Teil vor dem
=>
eine Wertdeklaration und kannimplicit
wie in jeder anderenval
Deklaration markiert werden, wenn Sie möchten . Hierrequest
muss es nicht markiert sein,implicit
damit die Typprüfung erfolgt. Auf diese Weise wird es jedoch als impliziter Wert für alle Methoden verfügbar , die es möglicherweise innerhalb der Funktion benötigen (und natürlich kann es auch explizit verwendet werden). . In diesem speziellen Fall wurde dies durchgeführt, weil diebindFromRequest
Methode für die Form- Klasse ein implizitesRequest
Argument erfordert .quelle
WARNUNG: Enthält Sarkasmus mit Bedacht! YMMV ...
Luigis Antwort ist vollständig und richtig. Dies ist nur, um es ein wenig zu erweitern, mit einem Beispiel dafür, wie Sie implizite Implikationen herrlich überbeanspruchen können , wie es in Scala-Projekten ziemlich häufig vorkommt. Eigentlich so oft, können Sie es wahrscheinlich sogar in einem der "Best Practice" -Handbücher finden.
quelle
Warum und wann sollten Sie den
request
Parameter markieren alsimplicit
:Einige Methoden, die Sie im Hauptteil Ihrer Aktion verwenden, verfügen über eine implizite Parameterliste , z. B. definiert Form.scala eine Methode:
Sie bemerken dies nicht unbedingt, wie Sie es einfach aufrufen würden.
myForm.bindFromRequest()
Sie müssen die impliziten Argumente nicht explizit angeben. Nein, Sie lassen den Compiler jedes Mal nach einem gültigen Kandidatenobjekt suchen, das übergeben werden soll, wenn es auf einen Methodenaufruf stößt, für den eine Instanz der Anforderung erforderlich ist. Da Sie tun eine Anfrage haben, alles , was Sie tun müssen, ist es so zu markierenimplicit
.Sie markieren es explizit als für die implizite Verwendung verfügbar .
Sie weisen den Compiler an, dass es "OK" ist, das vom Play-Framework gesendete Anforderungsobjekt (das wir mit dem Namen "request" angegeben haben, aber nur "r" oder "req" hätten verwenden können) zu verwenden, wo immer dies erforderlich ist, "schlau". .
siehst du es? es ist nicht da, aber es ist da!
Es passiert einfach, ohne dass Sie es manuell an jeder Stelle einstecken müssen, die es benötigt (aber Sie können es explizit übergeben, wenn Sie dies wünschen, egal ob es markiert ist
implicit
oder nicht):Ohne sie als implizite Markierung, würden Sie haben die oben zu tun. Wenn Sie es als implizit markieren, müssen Sie es nicht.
Wann sollten Sie die Anfrage als markieren
implicit
? Dies ist nur dann wirklich erforderlich, wenn Sie Methoden verwenden, die eine implizite Parameterliste deklarieren, die eine Instanz der Anforderung erwartet . Aber um es einfach zu halten, könnten Sie es sich zur Gewohnheit machen, die Anfrageimplicit
immer zu markieren . Auf diese Weise können Sie einfach schönen knappen Code schreiben.quelle
In Scala funktioniert implizit wie folgt :
Konverter
Parameterwert Injektor
Es gibt 3 Arten der impliziten Verwendung
Implizite Typkonvertierung : Konvertiert die fehlererzeugende Zuordnung in den beabsichtigten Typ
val x: String = "1"
val y: Int = x
String ist nicht der Untertyp von Int , daher tritt ein Fehler in Zeile 2 auf. Um den Fehler zu beheben, sucht der Compiler nach einer solchen Methode im Bereich, die ein implizites Schlüsselwort enthält, einen String als Argument verwendet und einen Int zurückgibt .
damit
Implizite Empfängerkonvertierung : Wir rufen im Allgemeinen die Eigenschaften des Empfängeraufrufobjekts auf, z. Methoden oder Variablen. Um eine Eigenschaft von einem Empfänger aufzurufen, muss die Eigenschaft Mitglied der Klasse / des Objekts dieses Empfängers sein.
Hier wird mahadi.haveTv einen Fehler erzeugen. Weil der Scala-Compiler zuerst nach der haveTv- Eigenschaft für den Mahadi- Empfänger sucht . Es wird nicht finden. Zweitens wird nach einer Methode im Gültigkeitsbereich mit implizitem Schlüsselwort gesucht, die das Mahadi-Objekt als Argument verwendet und das Johnny-Objekt zurückgibt . Aber es hat hier nicht. Es wird also ein Fehler entstehen . Aber das Folgende ist in Ordnung.
Implizite Parameterinjektion : Wenn wir eine Methode aufrufen und ihren Parameterwert nicht übergeben, verursacht dies einen Fehler. Der Scala-Compiler funktioniert folgendermaßen - zuerst wird versucht, einen Wert zu übergeben, es wird jedoch kein direkter Wert für den Parameter abgerufen.
Zweitens , wenn die Parameter jedes implizites Schlüsselwort hat , wird es für jeden aussieht val im Rahmen , die die haben gleiche Art von Wert. Wenn nicht, wird es Fehler verursachen.
Slove dieses Problem Compiler für eine aussieht implizite val den mit Typ Int , weil der Parameter a hat implizites Schlüsselwort .
Ein anderes Beispiel:
wir können es auch schreiben wie-
Da L hat einen impliziten Parameter und im Rahmen der körpereigenen Methode x gibt es einen impliziten lokalen Variable ( Parameter sind lokale Variablen ) ein , die die Parameter der ist , x , so in dem Körper der x - Methode der Methodensignatur Ls impliziter Argumentwert ist durch die eingereichten x - Methode der lokalen impliziten Variable (Parameter)
a
implizit .Damit
wird im Compiler so sein
Ein anderes Beispiel:
Dies führt zu Fehlern, da c in x {x => c} eine explizite Wertübergabe im Argument oder einen impliziten Wert im Gültigkeitsbereich erfordert .
Wir können also den Parameter des Funktionsliteral explizit implizit machen, wenn wir die Methode x aufrufen
Dies wurde in der Aktionsmethode von Play-Framework verwendet
Wenn Sie den Anforderungsparameter nicht explizit als implizit erwähnen, müssen Sie geschrieben worden sein.
quelle
Im obigen Fall sollte es auch eine
only one
implizite Funktion geben, deren Typ istdouble => Int
. Andernfalls wird der Compiler verwirrt und nicht richtig kompiliert.quelle
Ein sehr einfaches Beispiel für Implicits in Scala.
Implizite Parameter :
Hinweis: Hier
multiplier
wird implizit an die Funktion übergebenmultiply
. Fehlende Parameter für den Funktionsaufruf werden im aktuellen Bereich nach Typ gesucht, was bedeutet, dass Code nicht kompiliert wird, wenn keine implizite Variable vom Typ Int im Bereich vorhanden ist.Implizite Konvertierungen :
Hinweis: Wenn wir eine
multiply
Funktion aufrufen , die einen doppelten Wert übergibt, versucht der Compiler, die implizite Konvertierungsfunktion im aktuellen Bereich zu finden, dieInt
inDouble
(As functionmultiply
acceptInt
parameter) konvertiert wird . Wenn keine impliziteconvert
Funktion vorhanden ist, kompiliert der Compiler den Code nicht.quelle
Ich hatte genau die gleiche Frage wie Sie und ich denke, ich sollte anhand einiger wirklich einfacher Beispiele mitteilen, wie ich sie zu verstehen begann (beachten Sie, dass sie nur die gängigen Anwendungsfälle abdeckt).
In Scala gibt es zwei häufige Anwendungsfälle
implicit
.Beispiele sind wie folgt
Verwenden Sie es für eine Variable . Wie Sie sehen können
implicit
, wird die nächstgelegene Variable verwendet , wenn das Schlüsselwort in der letzten Parameterliste verwendet wird.Verwenden Sie es für eine Funktion . Wie Sie sehen können,
implicit
wird bei Verwendung der Funktion für die Funktion die nächstgelegene Typkonvertierungsmethode verwendet.Hoffe das kann helfen.
quelle