Je parcourais le didacticiel Scala Playframework et je suis tombé sur cet extrait de code qui m'a laissé perplexe:
def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Task.all(), errors)),
label => {
Task.create(label)
Redirect(routes.Application.tasks())
}
)
}
J'ai donc décidé d'enquêter et suis tombé sur ce post .
Je ne comprends toujours pas.
Quelle est la différence entre cela:
implicit def double2Int(d : Double) : Int = d.toInt
et
def double2IntNonImplicit(d : Double) : Int = d.toInt
à part le fait évident, ils ont des noms de méthode différents.
Quand devrais-je utiliser implicit
et pourquoi?
scala
syntax
playframework
keyword
Clive
la source
la source
Réponses:
J'expliquerai les principaux cas d'utilisation des implicites ci-dessous, mais pour plus de détails, voir le chapitre correspondant de la programmation dans Scala .
Paramètres implicites
La liste finale des paramètres d'une méthode peut être marquée
implicit
, ce qui signifie que les valeurs seront prises à partir du contexte dans lequel elles sont appelées. S'il n'y a pas de valeur implicite du bon type dans la portée, il ne sera pas compilé. Puisque la valeur implicite doit se résoudre en une seule valeur et pour éviter les conflits, c'est une bonne idée de rendre le type spécifique à son objectif, par exemple, ne nécessite pas vos méthodes pour trouver un impliciteInt
!exemple:
Conversions implicites
Lorsque le compilateur trouve une expression du mauvais type pour le contexte, il recherchera une
Function
valeur implicite d'un type qui lui permettra de vérifier le type. Donc, si unA
est requis et qu'il trouve unB
, il recherchera une valeur implicite de typeB => A
dans la portée (il vérifie également certains autres endroits comme dans les objets compagnonsB
etA
, s'ils existent). Puisquedef
s peut être "éta-développé" enFunction
objets, animplicit def xyz(arg: B): A
fera de même.Ainsi, la différence entre vos méthodes est que celle qui est marquée
implicit
sera insérée pour vous par le compilateur quand unDouble
est trouvé mais qu'unInt
est requis.fonctionnera de la même manière que
Dans la seconde, nous avons inséré la conversion manuellement; dans le premier, le compilateur faisait de même automatiquement. La conversion est requise en raison de l'annotation de type sur le côté gauche.
Concernant votre premier extrait de jeu:
Les actions sont expliquées sur cette page à partir de la documentation Play (voir aussi les documents API ). Vous utilisez
sur l'
Action
objet (qui est le compagnon du trait du même nom).Nous devons donc fournir une fonction comme argument, qui peut être écrit comme un littéral sous la forme
Dans un littéral de fonction, la partie précédant la
=>
est une déclaration de valeur, et peut être marquéeimplicit
si vous le souhaitez, comme dans toute autreval
déclaration. Ici, ilrequest
n'est pas nécessaire de marquerimplicit
cette valeur pour taper check, mais ce faisant, elle sera disponible comme valeur implicite pour toutes les méthodes qui pourraient en avoir besoin dans la fonction (et bien sûr, elle peut également être utilisée explicitement) . Dans ce cas particulier, cela a été fait car labindFromRequest
méthode de la classe Form requiert unRequest
argument implicite .la source
ATTENTION: contient judicieusement des sarcasmes! YMMV ...
La réponse de Luigi est complète et correcte. Celui-ci ne fait que l'étendre un peu avec un exemple de la façon dont vous pouvez glorieusement surexploiter les implicits , comme cela arrive assez souvent dans les projets Scala. En fait, si souvent, vous pouvez probablement le trouver dans l'un des guides des "meilleures pratiques" .
la source
Pourquoi et quand vous devez marquer le
request
paramètre commeimplicit
:Certaines méthodes que vous utiliserez dans le corps de votre action ont une liste de paramètres implicites comme, par exemple, Form.scala définit une méthode:
Vous ne le remarquez pas nécessairement comme vous l'appelleriez simplement.
myForm.bindFromRequest()
Vous n'avez pas à fournir explicitement les arguments implicites. Non, vous quittez le compilateur pour rechercher tout objet candidat valide à passer chaque fois qu'il rencontre un appel de méthode qui nécessite une instance de la demande. Puisque vous faire une demande disponible, tout ce que vous devez faire est de le marquer commeimplicit
.Vous le marquez explicitement comme disponible pour une utilisation implicite .
Vous indiquez au compilateur qu'il est "OK" d'utiliser l'objet de requête envoyé par le framework Play (que nous avons donné le nom "request" mais aurait pu utiliser simplement "r" ou "req") partout où cela était nécessaire, "en catimini" .
tu le vois? ce n'est pas là, mais il est là!
Cela se produit simplement sans que vous ayez à l'insérer manuellement dans tous les endroits où vous en avez besoin (mais vous pouvez le transmettre explicitement, si vous le souhaitez, qu'il soit marqué
implicit
ou non):Sans le marquer comme implicite, vous devrez faire ce qui précède. Le marquer comme implicite n'est pas obligatoire.
Quand devez-vous marquer la demande
implicit
? Vous ne devez vraiment le faire que si vous utilisez des méthodes qui déclarent une liste de paramètres implicite attendant une instance de la demande . Mais pour faire simple, vous pouvez simplement prendre l'habitude deimplicit
toujours marquer la demande . De cette façon, vous pouvez simplement écrire un beau code laconique.la source
In scala fonctionne implicitement comme :
Convertisseur
Injecteur de valeur de paramètre
Il existe 3 types d'utilisation implicite
Conversion de type implicite : il convertit l'affectation produisant l'erreur en type prévu
val x: String = "1"
val y: Int = x
La chaîne n'est pas le sous-type d'Int , donc l'erreur se produit à la ligne 2. Pour résoudre l'erreur, le compilateur recherchera une telle méthode dans la portée qui a un mot clé implicite et prend une chaîne comme argument et renvoie un Int .
alors
Conversion de récepteur implicite : Nous avons généralement par les propriétés de l'objet d'appel du récepteur, par exemple. méthodes ou variables. Ainsi, pour appeler une propriété par un récepteur, la propriété doit être membre de la classe / de l'objet de ce récepteur.
Ici, mahadi.haveTv produira une erreur. Parce que le compilateur scala va d' abord chercher la haveTv propriété à Mahadi récepteur. Il ne trouvera pas. Deuxièmement, il recherchera une méthode dans la portée ayant un mot clé implicite qui prend l' objet Mahadi comme argument et renvoie l' objet Johnny . Mais il n'a pas ici. Cela créera donc une erreur . Mais ce qui suit est correct.
Injection implicite de paramètres : si nous appelons une méthode et ne transmettons pas sa valeur de paramètre, cela provoquera une erreur. Le compilateur scala fonctionne comme ceci - le premier essaiera de transmettre la valeur, mais il n'obtiendra aucune valeur directe pour le paramètre.
Deuxièmement, si le paramètre a un mot clé implicite, il recherchera tout val dans la portée qui a le même type de valeur. Sinon, cela provoquera une erreur.
Pour résoudre ce problème, le compilateur recherchera une valeur implicite ayant le type Int car le paramètre a a un mot clé implicite .
Un autre exemple:
on peut aussi l'écrire comme
Parce que l a un paramètre implicite et dans la portée du corps de la méthode x , il existe une variable locale implicite (les paramètres sont des variables locales ) a qui est le paramètre de x , donc dans le corps de la méthode x la valeur de l'argument implicite de la signature de méthode est déposée par la variable locale de la méthode x implicite (paramètre)
a
implicitement .Alors
sera dans le compilateur comme celui-ci
Un autre exemple:
cela provoquera une erreur, car c dans x {x => c} a besoin d'un argument de valeur explicite ou d'une valeur implicite dans la portée .
Nous pouvons donc rendre le paramètre de la fonction littérale explicitement implicite lorsque nous appelons la méthode x
Cela a été utilisé dans la méthode d'action de Play-Framework
si vous ne mentionnez pas explicitement le paramètre de demande comme implicite, alors vous devez avoir été écrit-
la source
De plus, dans le cas ci-dessus, il devrait y avoir
only one
une fonction implicite dont le type estdouble => Int
. Sinon, le compilateur devient confus et ne compile pas correctement.la source
Un exemple très basique de Implicits in scala.
Paramètres implicites :
Remarque: ici
multiplier
sera implicitement transmis à la fonctionmultiply
. Les paramètres manquants de l'appel de fonction sont recherchés par type dans la portée actuelle, ce qui signifie que le code ne sera pas compilé s'il n'y a pas de variable implicite de type Int dans la portée.Conversions implicites :
Remarque: Lorsque nous appelons une
multiply
fonction en passant une valeur double, le compilateur essaiera de trouver la fonction implicite de conversion dans la portée actuelle, qui se convertitInt
enDouble
(en tant que fonctionmultiply
accepte leInt
paramètre). S'il n'y a pas deconvert
fonction implicite , le compilateur ne compilera pas le code.la source
J'avais exactement la même question que vous et je pense que je devrais partager comment j'ai commencé à la comprendre par quelques exemples très simples (notez que cela ne couvre que les cas d'utilisation courants).
Scala utilise deux cas d'utilisation courants
implicit
.Les exemples sont les suivants
L'utiliser sur une variable . Comme vous pouvez le voir, si le
implicit
mot-clé est utilisé dans la dernière liste de paramètres, la variable la plus proche sera utilisée.L'utiliser sur une fonction . Comme vous pouvez le voir, si le
implicit
est utilisé sur la fonction, la méthode de conversion de type la plus proche sera utilisée.J'espère que cela peut vous aider.
la source