Opzione Scala (null) prevista come None ma ho ottenuto Some (0)


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

Qual è il modo sicuro per convertire null: java.lang.Integerin Scala Option[Int]?


1
Potete per favore incollare il codice nella domanda?
Виталий Олегович

Risposte:


17

Stai mescolando Inte java.lang.Integercosì

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

si converte implicitamente in

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

che diventa

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

così

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

Se vuoi lavorare con java.lang.Integer, allora scrivi

val o: Option[java.lang.Integer] = Option(i)
// o: Option[Integer] = None

2
Questo è stato recentemente chiesto da qualche parte, quindi è un vero gotcha. Forse il problema si basa sull'inferenza: mi Option[Integer](i).map(_.intValue)sembra molto idiomatico, dal momento che dice cosa sta facendo. Inoltre, utilizzare -Xlintper visualizzare l'avviso per il val o!
som-snytt

Per evitare un round trip di boxe, `val x: Option [Int] = Option (i) .asInstanceOf [Option [Int]]` dove Integerviene inferito.
som-snytt

7

Questo sembra accadere perché stai creando Optione convertendolo in un Intunico passaggio (la risposta di @ MarioGalic spiega perché questo sta accadendo).

Questo fa quello che vuoi:

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)

Sull'altra risposta, ho suggerito _.intValue. Immagino che salvi solo la chiamata di conversione.
som-snytt

1

Di fronte allo stesso problema prima. Questo comportamento discutibile è noto al team Scala. Sembra che cambiarlo si rompa qualcosa altrove. Vedi https://github.com/scala/bug/issues/11236 e https://github.com/scala/scala/pull/5176 .


2
Il comportamento veramente discutibile sta trattando nullcome un numero intero. Questo è presumibilmente una sbronza da Ccui è OK assegnare 0a un puntatore. Ma questo non significa che il puntatore risultante sia 0, quindi è sconsigliabile passare da uno all'altro C.
Tim

Integermolto probabilmente proviene dal codice Java, quindi "non trattare null come un numero intero" non è un consiglio attuabile. E controlliamo esplicitamente questo numero intero per nullità usando Option.apply. In questo modo otteniamo output imprevisti senza fare esplicitamente operazioni non sicure.
simpadjo,

Il punto è che non si può incolpare Scala per "comportamenti discutibili" quando la causa principale è Java. Il consiglio attuabile è di avere una conversione esplicita da tipi Java a tipi Scala equivalenti piuttosto che usare una conversione implicita. (Quindi JavaConverterspiuttosto che JavaConversion)
Tim

1
Bene, posso e biasimo Scala per non aver emesso un errore / avviso di compilazione in questo caso. Anche il crash del runtime sarebbe meglio. Anche nella mia compagnia solo 2 sviluppatori con oltre 5 anni di esperienza in Scala hanno riscontrato questo problema.
simpadjo,

1
@Tim Sarebbe molto facile ottenere un arresto anomalo del runtime, semplicemente chiamando theInteger.intValue(). Evitare l'incidente è ciò che costa un controllo di runtime aggiuntivo. Nelle versioni precedenti di Scala, questa conversione ha effettivamente prodotto un NPE; è stato segnalato come un bug e corretto per il comportamento corrente. Non sono un esperto di Scala, ma ho scavato scala-dev # 355 e scala # 5176 come contesto storico.
amalloy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.