Opción de Scala (nula) esperada como None pero obtuve Some (0)

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

¿Cuál es la forma segura de convertir null: java.lang.Integera Scala Option[Int]?

anandhu sreekumar
fuente
1
¿Puedes pegar tu código en la pregunta?
Виталий Олегович

Respuestas:

17

Estás mezclando Inty java.lang.Integerasí

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

se convierte implícitamente a

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

que se convierte

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

así

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

Si quieres trabajar java.lang.Integer, entonces escribe

val o: Option[java.lang.Integer] = Option(i)
// o: Option[Integer] = None
Mario Galic
fuente
2
Esto se preguntó recientemente en alguna parte, así que es un verdadero problema. Tal vez el problema se basa en la inferencia: me Option[Integer](i).map(_.intValue)parece muy idiota, ya que dice lo que está haciendo. Además, use -Xlintpara ver la advertencia de val o!
som-snytt
Para evitar un viaje redondo de boxeo, `val x: Opción [Int] = Opción (i) .asInstanceOf [Opción [Int]]` donde Integerse infiere.
som-snytt
7

Esto parece estar sucediendo porque está creando Optiony convirtiéndolo en un Intsolo paso (la respuesta de @ MarioGalic explica por qué sucede esto).

Esto hace lo que quieres:

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
fuente
En la otra respuesta, sugerí _.intValue. Supongo que solo guarda la llamada de conversión.
som-snytt
1

Enfrenté el mismo problema antes. Este comportamiento cuestionable es conocido por el equipo de Scala. Parece que cambiarlo rompe algo en otra parte. Consulte https://github.com/scala/bug/issues/11236 y https://github.com/scala/scala/pull/5176 .

simpadjo
fuente
2
El comportamiento realmente cuestionable es tratar nullcomo un número entero. Presumiblemente, esto es una resaca desde Cdonde está bien asignar 0a un puntero. Pero esto no significa que el puntero resultante lo sea 0, por lo que es dudoso cambiar entre los dos incluso C.
Tim
IntegerLo más probable es que provenga del código Java, por lo que "no tratar nulo como un entero" no es un consejo práctico. Y verificamos explícitamente este número entero para la nulabilidad usando Option.apply. Entonces obtenemos resultados inesperados sin hacer explícitamente ninguna operación insegura.
simpadjo
El punto es que no se puede culpar a Scala por "comportamiento cuestionable" cuando la causa raíz es Java. El consejo práctico es tener una conversión explícita de los tipos de Java a los tipos de Scala equivalentes en lugar de usar la conversión implícita. (Por lo tanto, en JavaConverterslugar de JavaConversion)
Tim
1
Bueno, puedo y culpo a Scala por no emitir un error / advertencia de compilación en este caso. Incluso el choque en tiempo de ejecución sería mejor. Incluso en mi empresa, solo 2 desarrolladores con más de 5 años de experiencia en Scala han tenido este problema.
simpadjo
1
@Tim Sería muy fácil obtener un bloqueo en tiempo de ejecución, simplemente llamando theInteger.intValue(). Evitar ese bloqueo es lo que cuesta una verificación de tiempo de ejecución adicional. En versiones anteriores de Scala, esta conversión de hecho produjo un NPE; se informó como un error y se corrigió al comportamiento actual. No soy un experto en Scala, pero desenterré scala-dev # 355 y scala # 5176 como contexto histórico.
amalloy