Opsi Scala (null) diharapkan sebagai Tidak Ada tetapi saya mendapatkan Beberapa (0)

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

Apa cara aman untuk mengonversi null: java.lang.Integerke Scala Option[Int]?

anandhu sreekumar
sumber
1
Bisakah Anda menempelkan kode Anda dalam pertanyaan?
Виталий Олегович

Jawaban:

17

Anda mencampur Intdan java.lang.Integersebagainya

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

secara implisit mengkonversi ke

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

yang menjadi

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

jadi

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

Jika Anda ingin bekerja dengannya java.lang.Integer, maka tulislah

val o: Option[java.lang.Integer] = Option(i)
// o: Option[Integer] = None
Mario Galic
sumber
2
Ini baru-baru ini diminta di suatu tempat, jadi itu benar-benar gotcha. Mungkin masalahnya bergantung pada kesimpulan: Option[Integer](i).map(_.intValue)tampaknya paling idiomatis bagi saya, karena ia mengatakan apa yang dilakukannya. Juga, gunakan -Xlintuntuk melihat peringatan untuk val o!
som-snytt
Untuk menghindari pulang pergi tinju, `val x: Opsi [Int] = Opsi (i) .asInstanceOf [Opsi [Int]]` di mana Integerdisimpulkan.
som-snytt
7

Ini tampaknya terjadi karena Anda membuat Option, dan mengubahnya menjadi Intdalam satu langkah ( jawaban @ MarioGalic menjelaskan mengapa ini terjadi).

Ini melakukan apa yang Anda inginkan:

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
sumber
Pada jawaban yang lain, saya menyarankan _.intValue. Saya kira itu hanya menyimpan panggilan konversi.
som-snytt
1

Menghadapi masalah yang sama sebelumnya. Perilaku yang dipertanyakan ini diketahui oleh tim Scala. Tampaknya mengubahnya merusak sesuatu di tempat lain. Lihat https://github.com/scala/bug/issues/11236 dan https://github.com/scala/scala/pull/5176 .

simpadjo
sumber
2
Perilaku yang benar-benar dipertanyakan adalah memperlakukan nullsebagai bilangan bulat. Ini mungkin adalah hangover dari Ctempat OK untuk menetapkan 0ke pointer. Tapi ini tidak berarti bahwa pointer yang dihasilkan adalah 0, jadi sangat cerdik untuk beralih di antara keduanya C.
Tim
Integerpaling mungkin berasal dari kode Java jadi 'jangan perlakukan null sebagai integer' bukan saran yang bisa ditindaklanjuti. Dan kami secara eksplisit memeriksa Integer ini untuk menggunakan nullability Option.apply. Jadi kami mendapatkan hasil yang tidak terduga tanpa melakukan operasi yang tidak aman secara eksplisit.
simpadjo
Intinya adalah bahwa Anda tidak dapat menyalahkan Scala untuk "perilaku yang dipertanyakan" ketika akar penyebabnya adalah Java. Saran yang dapat ditindaklanjuti adalah memiliki konversi eksplisit dari tipe Java ke tipe Scala yang setara daripada menggunakan konversi implisit. (Karena itu JavaConvertersdaripada JavaConversion)
Tim
1
Yah, saya bisa dan saya menyalahkan Scala karena tidak memancarkan kesalahan kompilasi / peringatan dalam kasus ini. Bahkan crash runtime akan lebih baik. Bahkan di perusahaan saya sendiri 2 pengembang dengan pengalaman 5+ tahun di Scala telah mengatasi masalah ini.
simpadjo
1
@Tim Akan sangat mudah untuk mendapatkan crash runtime, hanya dengan menelepon theInteger.intValue(). Menghindari kecelakaan itu adalah apa yang menyebabkan biaya pemeriksaan runtime tambahan. Dalam versi Scala yang lebih lama, konversi ini memang menghasilkan NPE; itu dilaporkan sebagai bug, dan diperbaiki dengan perilaku saat ini. Saya bukan ahli Scala, tetapi saya menggali scala-dev # 355 dan scala # 5176 sebagai konteks sejarah.
amalloy