Option Scala (null) attendue comme Aucune mais j'en ai eu (0)

9
val i: java.lang.Integer = null
val o: Option[Int] = Option(i) // This yields Some(0)

Quel est le moyen sûr de se convertir null: java.lang.Integerà Scala Option[Int]?

anandhu sreekumar
la source
1
Pouvez-vous s'il vous plaît coller votre code dans la question?
Виталий Олегович

Réponses:

17

Vous mixez Intet java.lang.Integerainsi

val i: java.lang.Integer = null
val o: Option[Int] = Option(i)

convertit implicitement en

val o: Option[Int] = Option(Integer2int(i))

qui devient

val o: Option[Int] = Option(null.asInstanceOf[Int])

Donc

val o: Option[Int] = Some(0)

Si vous voulez travailler avec java.lang.Integer, écrivez

val o: Option[java.lang.Integer] = Option(i)
// o: Option[Integer] = None
Mario Galic
la source
2
Cela a été récemment demandé quelque part, donc c'est un vrai piège. Peut-être que le problème repose sur l'inférence: cela Option[Integer](i).map(_.intValue)me semble le plus idiomatique, car il dit ce qu'il fait. Utilisez également -Xlintpour voir l'avertissement du val o!
som-snytt
Pour éviter un aller-retour de boxe, `val x: Option [Int] = Option (i) .asInstanceOf [Option [Int]]` où Integerest déduit.
som-snytt
7

Cela semble se produire parce que vous créez le Option, et le convertissez en un Inten une seule étape (@ MarioGalic's réponse de explique pourquoi cela se produit).

Cela fait ce que vous voulez:

scala> val o: java.lang.Integer = null
o: Integer = null

scala> val i: Option[Int] = Option(o).map(_.toInt)
i: Option[Int] = None

scala> val o1: java.lang.Integer = 1
o1: Integer = 1

scala> val i1: Option[Int] = Option(o1).map(_.toInt)
i1: Option[Int] = Some(1)
Jack Leow
la source
Sur l'autre réponse, j'ai suggéré _.intValue. Je suppose que cela enregistre uniquement l'appel de conversion.
som-snytt
1

Face au même problème auparavant. Ce comportement douteux est connu de l'équipe Scala. Il semble que le changer brise quelque chose ailleurs. Voir https://github.com/scala/bug/issues/11236 et https://github.com/scala/scala/pull/5176 .

simpadjo
la source
2
Le comportement vraiment discutable traite nullcomme un entier. Il s'agit vraisemblablement d'une gueule de bois d' Coù il est OK d'assigner 0à un pointeur. Mais cela ne signifie pas que le pointeur résultant est 0, il est donc douteux de basculer entre les deux même en C.
Tim
Integerprovient très probablement du code Java, donc «ne pas traiter null comme un entier» n'est pas un conseil exploitable. Et nous vérifions explicitement la nullité de cet entier à l'aide de Option.apply. Nous obtenons donc une sortie inattendue sans effectuer explicitement des opérations dangereuses.
simpadjo
Le fait est que vous ne pouvez pas blâmer Scala pour "comportement douteux" lorsque la cause première est Java. Le conseil pratique est d'avoir une conversion explicite des types Java vers les types Scala équivalents plutôt que d'utiliser une conversion implicite. (D'où JavaConvertersplutôt que JavaConversion)
Tim
1
Eh bien, je peux et je blâme Scala de ne pas avoir émis d'erreur / avertissement de compilation dans ce cas. Même un crash d'exécution serait mieux. Même dans ma seule entreprise, 2 développeurs avec plus de 5 ans d'expérience à Scala ont rencontré ce problème.
simpadjo
1
@Tim Il serait très facile d'obtenir un crash d'exécution, en appelant simplement theInteger.intValue(). Éviter ce plantage est ce qui coûte une vérification supplémentaire de l'exécution. Dans les anciennes versions de Scala, cette conversion produisait en effet un NPE; il a été signalé comme bogue et corrigé au comportement actuel. Je ne suis pas un expert Scala, mais j'ai déterré scala-dev # 355 et scala # 5176 comme contexte historique.
amalloy