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]?


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

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)

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 .


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.