Opção Scala (nula) esperada como Nenhuma, mas recebi Alguma (0)

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

Qual é a maneira segura de converter null: java.lang.Integerpara Scala Option[Int]?

anandhu sreekumar
fonte
11
Você pode colar o seu código na pergunta?
Виталий Олегович

Respostas:

17

Você está misturando Inte java.lang.Integerentão

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

converte implicitamente em

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

que se torna

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

portanto

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

Se você deseja trabalhar java.lang.Integer, escreva

val o: Option[java.lang.Integer] = Option(i)
// o: Option[Integer] = None
Mario Galic
fonte
2
Isso foi solicitado recentemente em algum lugar, por isso é uma verdadeira pegadinha. Talvez o problema esteja na inferência: Option[Integer](i).map(_.intValue)parece-me mais idiomático, pois diz o que está fazendo. Além disso, use -Xlintpara ver o aviso para o val o!
som-snytt 9/03
Para evitar uma ida e volta de boxe, `val x: Option [Int] = Opção (i) .asInstanceOf [Option [Int]]` onde Integeré inferido.
som-snytt 9/03
7

Isso parece estar acontecendo porque você está criando Optione convertendo-o Intem uma etapa (a resposta de @ MarioGalic explica por que isso está acontecendo).

Isso faz o que você deseja:

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
fonte
Por outro lado, sugeri _.intValue. Acho que só salva a chamada de conversão.
som-snytt 9/03
1

Enfrentou o mesmo problema antes. Esse comportamento questionável é conhecido pela equipe Scala. Parece que mudá-lo quebra algo em outro lugar. Consulte https://github.com/scala/bug/issues/11236 e https://github.com/scala/scala/pull/5176 .

simpadjo
fonte
2
O comportamento realmente questionável é tratar nullcomo um número inteiro. Presumivelmente, é uma ressaca de Conde não há problema em atribuir 0a um ponteiro. Mas isso não significa que o ponteiro resultante seja 0, portanto, é complicado alternar entre os dois C.
Tim
Integerprovavelmente veio do código Java, portanto, 'não trate nulo como um número inteiro' não é um conselho acionável. E verificamos explicitamente esse número inteiro quanto à nulidade usando Option.apply. Portanto, obtemos resultados inesperados sem executar explicitamente operações inseguras.
simpadjo 9/03
O ponto é que você não pode culpar a Scala por "comportamento questionável" quando a causa raiz é Java. O conselho acionável é ter uma conversão explícita dos tipos Java para os tipos Scala equivalentes, em vez de usar a conversão implícita. (Portanto, em JavaConvertersvez de JavaConversion)
Tim
11
Bem, eu posso e culpo o Scala por não emitir erro / aviso de compilação neste caso. Mesmo falha de tempo de execução seria melhor. Mesmo na minha empresa, apenas 2 desenvolvedores com mais de 5 anos de experiência em Scala atingiram esse problema.
simpadjo 9/03
11
@ Tim Seria muito fácil obter uma falha de tempo de execução, simplesmente chamando theInteger.intValue(). Evitar essa falha é o que custa uma verificação de tempo de execução extra. Nas versões mais antigas do Scala, essa conversão realmente produziu um NPE; foi relatado como um bug e corrigido para o comportamento atual. Não sou especialista em Scala, mas descobri o scala-dev # 355 e o scala # 5176 como contexto histórico.
amalloy 9/03