En langage Groovy, il est très simple de vérifier null
ou false
comme:
code groovy:
def some = getSomething()
if(some) {
// do something with some as it is not null or emtpy
}
Dans Groovy si some
est null
ou est une chaîne vide ou est zéro nombre etc. sera évalué à false
. Quelle est la méthode concise similaire pour tester null
ou false
dans Scala? Quelle est la réponse simple à cette partie de la question en supposant que some
est simplement du type Java String?
Une autre méthode encore meilleure en groovy est:
def str = some?.toString()
ce qui signifie que si some
n'est pas null
, alors la méthode toString
sur some
serait invoquée au lieu de lancer NPE dans le cas où some
serait null
. Qu'est-ce qui est similaire à Scala?
Ce qui vous manque peut-être, c'est qu'une fonction comme getSomething
dans Scala ne renverrait probablement pas null, chaîne vide ou nombre zéro. Une fonction qui pourrait ou non renvoyer une valeur significative aurait pour retour Option
- elle renverrait Some(meaningfulvalue)
ou None
.
Vous pouvez alors vérifier cela et gérer la valeur significative avec quelque chose comme
val some = getSomething()
some match {
case Some(theValue) => doSomethingWith(theValue)
case None => println("Whoops, didn't get anything useful back")
}
Ainsi, au lieu d'essayer de coder la valeur "échec" dans la valeur de retour, Scala prend en charge de manière spécifique le cas commun "renvoyer quelque chose de significatif ou d'indiquer un échec".
Cela dit, Scala est interopérable avec Java, et Java renvoie les valeurs NULL des fonctions tout le temps. Si getSomething
est une fonction Java qui renvoie la valeur null, il existe un objet fabrique qui créera Some ou None à partir de la valeur renvoyée.
Alors
val some = Option(getSomething())
some match {
case Some(theValue) => doSomethingWith(theValue)
case None => println("Whoops, didn't get anything useful back")
}
... ce qui est assez simple, je prétends, et n'ira pas NPE sur vous.
Les autres réponses font des choses intéressantes et idiomatiques, mais c'est peut-être plus que ce dont vous avez besoin maintenant.
Boolean
ne peut pas être null
, à moins d’être passé en paramètre de type. La manière de gérer null
consiste à le convertir en un Option
, puis à utiliser tous les éléments Option
. Par exemple:
Option(some) foreach { s => println(s) }
Option(some) getOrElse defaultValue
Puisque Scala est de type statique, une chose ne peut pas être " une chaîne nulle ou une chaîne vide, ou est un nombre nul, etc. ". Vous pouvez passer une Any
qui peut être n'importe laquelle de ces choses, mais vous devrez alors faire correspondre chaque type pour pouvoir faire quoi que ce soit d’utile avec elle de toute façon. Si vous vous trouvez dans cette situation, vous ne faites probablement pas de Scala idiomatique.
Dans Scala, les expressions que vous avez décrites signifient qu'une méthode appelée ?
est appelée sur un objet appelé some
. Régulièrement, les objets n’ont pas de méthode appelée ?
. Vous pouvez créer votre propre conversion implicite en un objet avec une méthode ?
qui vérifie null
ness.
implicit def conversion(x: AnyRef) = new {
def ? = x ne null
}
En gros, tout ce qui précède convertit tout objet sur lequel vous appelez la méthode ?
en expression du côté droit de la méthode conversion
(qui a a la méthode ?
). Par exemple, si vous faites cela:
"".?
le compilateur détecte qu'un objet String
n'a pas de méthode ?
et le réécrit dans:
conversion("").?
Illustré dans un interpréteur (notez que vous pouvez omettre .
lorsque vous appelez des méthodes sur des objets):
scala> implicit def any2hm(x: AnyRef) = new {
| def ? = x ne null
| }
any2hm: (x: AnyRef)Java.lang.Object{def ?: Boolean}
scala> val x: String = "!!"
x: String = "!!"
scala> x ?
res0: Boolean = true
scala> val y: String = null
y: String = null
scala> y ?
res1: Boolean = false
Pour que vous puissiez écrire:
if (some ?) {
// ...
}
Ou vous pouvez créer une conversion implicite en un objet avec une méthode ?
qui appelle la méthode spécifiée sur l'objet si l'argument n'est pas null
- procédez comme suit:
scala> implicit def any2hm[T <: AnyRef](x: T) = new {
| def ?(f: T => Unit) = if (x ne null) f(x)
| }
any2hm: [T <: AnyRef](x: T)Java.lang.Object{def ?(f: (T) => Unit): Unit}
scala> x ? { println }
!!
scala> y ? { println }
afin que vous puissiez ensuite écrire:
some ? { _.toString }
En vous appuyant (de manière récursive) sur la réponse de soc, vous pouvez appliquer une correspondance de motif à x
dans les exemples ci-dessus pour préciser ce que ?
fait en fonction du type de x
. :RÉ
Si vous utilisez l'opérateur de coalescence null-safe de extempore , vous pouvez écrire votre exemple str
sous la forme suivante:
val str = ?:(some)(_.toString)()
Cela vous permet également de chaîner sans vous soucier de null
s (donc "coalescing"):
val c = ?:(some)(_.toString)(_.length)()
Bien entendu, cette réponse ne concerne que la deuxième partie de votre question.
Ce que vous demandez, c'est quelque chose dans la ligne de Safe Navigation Operator (?.) de Groovy, et gem de Ruby, ou variante d'accesseur de l'opérateur existentiel (?.) de CoffeeScript . Dans de tels cas, j'utilise généralement la méthode ?
de mon RichOption[T]
, qui est définie comme suit
class RichOption[T](option: Option[T]) {
def ?[V](f: T => Option[V]): Option[V] = option match {
case Some(v) => f(v)
case _ => None
}
}
implicit def option2RichOption[T](option: Option[T]): RichOption[T] =
new RichOption[T](option)
et utilisé comme suit
scala> val xs = None
xs: None.type = None
scala> xs.?(_ => Option("gotcha"))
res1: Option[Java.lang.String] = None
scala> val ys = Some(1)
ys: Some[Int] = Some(1)
scala> ys.?(x => Some(x * 2))
res2: Option[Int] = Some(2)
Vous pouvez écrire vous-même un wrapper ou utiliser un type Option.
Je ne voudrais vraiment pas vérifier pour null
cependant. S'il y a une null
quelque part, vous devriez la corriger et ne pas construire de contrôles autour d'elle.
S'appuyant sur la réponse d'axel22:
implicit def any2hm(x: Any) = new {
def ? = x match {
case null => false
case false => false
case 0 => false
case s: String if s.isEmpty => false
case _ => true
}
}
Edit: Cela semble planter le compilateur ou ne fonctionne pas. Je vais enquêter.