Opcja Scala (null) oczekiwana jako Brak, ale dostałem Trochę (0)


Odpowiedzi:


17

Mieszacie Inti java.lang.Integertak dalej

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

pośrednio konwertuje na

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

który staje się

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

a zatem

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

Jeśli chcesz pracować java.lang.Integer, napisz

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

2
Niedawno gdzieś o to pytano, więc to prawdziwa gotcha. Być może problem polega na wnioskowaniu: Option[Integer](i).map(_.intValue)wydaje mi się najbardziej idiomatyczny, ponieważ mówi, co robi. Użyj także, -Xlintaby zobaczyć ostrzeżenie dla val o!
som-snytt

Aby uniknąć obstawiania boksu, Integerwywnioskowano `val x: Opcja [Int] = Opcja (i) .asInstanceOf [Opcja [Int]]`
som-snytt

7

To wydaje się dzieje dlatego, że tworzenie Optioni przekształcenie go do Intw jednym kroku (@ MarioGalic za odpowiedź wyjaśnia, dlaczego tak się dzieje).

Robi to, co chcesz:

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)

Z drugiej strony zasugerowałem _.intValue. Wydaje mi się, że zapisuje tylko konwersję.
som-snytt

1

Wcześniej ten sam problem. To wątpliwe zachowanie jest znane zespołowi Scali. Wygląda na to, że zmiana go psuje coś innego. Zobacz https://github.com/scala/bug/issues/11236 i https://github.com/scala/scala/pull/5176 .


2
Naprawdę wątpliwe zachowanie traktuje się nulljako liczbę całkowitą. Jest to prawdopodobnie kac, z Cktórego można przypisać 0wskaźnik. Ale to nie znaczy, że wynikowy wskaźnik jest 0taki, więc przełączanie się między nimi jest niejasne C.
Tim

Integernajprawdopodobniej pochodzi z kodu Java, więc „nie traktuj wartości null jako liczby całkowitej” nie jest praktyczną radą. I jawnie sprawdzamy tę liczbę całkowitą pod kątem używania zerowalności Option.apply. Otrzymujemy więc nieoczekiwany wynik bez jawnego wykonywania niebezpiecznych operacji.
simpadjo

Chodzi o to, że nie można winić Scali za „wątpliwe zachowanie”, gdy główną przyczyną jest Java. Poradą praktyczną jest jawna konwersja z typów Java na równoważne typy Scala zamiast korzystania z niejawnej konwersji. (Stąd JavaConvertersraczej niż JavaConversion)
Tim

1
Cóż, mogę i obwiniam Scalę za to, że w tym przypadku nie wyemitował błędu kompilacji / ostrzeżenia. Nawet awaria środowiska uruchomieniowego byłaby lepsza. Nawet w mojej samej firmie 2 programistów z ponad 5-letnim doświadczeniem w Scali dotknęło tego problemu.
simpadjo

1
@Tim Bardzo łatwo byłoby uzyskać awarię środowiska wykonawczego, po prostu dzwoniąc theInteger.intValue(). Uniknięcie tej awarii kosztuje dodatkowe sprawdzenie środowiska wykonawczego. W starszych wersjach Scali ta konwersja rzeczywiście spowodowała powstanie NPE; został zgłoszony jako błąd i naprawiony do bieżącego zachowania. Nie jestem ekspertem Scala, ale wykopałem scala-dev # 355 i scala # 5176 jako kontekst historyczny.
amalloy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.