Option monade dans scala
-
28-09-2019 - |
Question
comment on entend au travail Option monade? Je surfe scala api et il est un exemple (je veux dire le second),
En raison de la façon dont des travaux de compréhension, si None est retourné de request.getParameter, les résultats entiers d'expression dans Aucun
Mais quand j'essaie ce code:
val upper = for {
name <- None //request.getParameter("name")
trimmed <- Some(name.trim)
upper <- Some(trimmed.toUpperCase) if trimmed.length != 0
} yield upper
println(upper.getOrElse(""))
je reçois une erreur de compilation. Comment est-ce censé fonctionner?
La solution
Vous obtenez une erreur de compilation à cause de cela
name <- None
De cette façon, le type de None
est réglé sur None.type
et la name
variable est inférées à être de type Nothing
. (C'est, il aurait ce type si elle existait réellement, mais évidemment la compréhension pour ne même pas à la création lors de l'exécution.) Par conséquent, aucune name.trim
méthode existe et il ne compilera pas.
Si vous aviez request.getParameter("name")
disponible, son type serait Option[String]
, name
aurait potentiellement le type String
et name.trim
compilerait.
Vous pouvez contourner ce problème en spécifiant le type de None
:
name <- None: Option[String]
Autres conseils
Pour développer la réponse de Kevin, vous pouvez éviter les valeurs d'emballage dans Some()
en utilisant l'opérateur de =
au lieu de l'opérateur <-
:
val upper = for {
name <- None: Option[String] //request.getParameter("name")
trimmed = name.trim
upper = trimmed.toUpperCase if trimmed nonEmpty
} yield upper
Le pour-comprendre compilera à quelque chose de très similaire à la version de Kevin, mais je trouve souvent plus clair d'utiliser map
et filter
explicitement à éviter l'encombrement (par exemple, les noms de variables supplémentaires) que rien d'ajouter au contenu sémantique de l'expression.
Pour développer la réponse de Debilski, vous pouvez aussi ne pas besoin d'envelopper explicitement les valeurs suivantes dans Some()
, la seule valeur que vous êtes réellement sur la cartographie est le name
d'origine.
Une meilleure approche serait d'utiliser les opérations de map
et filter
directement au lieu d'un pour-compréhension:
NOTE: dans les coulisses, le compilateur Scala convertira un pour-compréhension à une combinaison de carte / flatMap / filtre de toute façon, cette approche ne sera jamais moins efficace qu'un pour-compréhension, et pourrait bien être plus efficace
def clean(x:Option[String]) = x map { _.trim.toUpperCase } filterNot { _.isEmpty }
val param = None : Option[String] // request.getParameter("name")
println( clean(param).getOrElse("") )