Scala Option (null) คาดว่าจะเป็น None แต่ฉันได้รับบางส่วน (0)


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

วิธีที่ปลอดภัยในการเปลี่ยนnull: java.lang.Integerเป็น Scala Option[Int]คืออะไร?


1
คุณกรุณาวางรหัสในคำถามได้ไหม
ВиталийОлегович

คำตอบ:


17

คุณกำลังผสมIntและjava.lang.Integerดังนั้น

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

แปลงโดยปริยายเป็น

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

ซึ่งกลายเป็น

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

ดังนั้น

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

หากคุณต้องการทำงานกับjava.lang.Integerเขียนแล้ว

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

2
นี่เพิ่งถูกถามที่ไหนสักแห่งดังนั้นจึงเป็น gotcha จริง บางทีปัญหานั้นขึ้นอยู่กับการอนุมาน: Option[Integer](i).map(_.intValue)ดูเหมือนเป็นเรื่องแปลกที่สุดสำหรับฉันเพราะมันบอกว่ามันกำลังทำอะไรอยู่ นอกจากนี้ใช้-Xlintเพื่อดูคำเตือนสำหรับval o!
som-snytt

เพื่อหลีกเลี่ยงการมวยไปกลับ `val x: ตัวเลือก [Int] = ตัวเลือก (i) .asInstanceOf [ตัวเลือก [Int]]` โดยที่Integerอนุมานไว้
som-snytt

7

ดูเหมือนว่าจะเกิดขึ้นเพราะคุณกำลังสร้างOptionและแปลงเป็นIntขั้นตอนเดียว ( คำตอบของ @ MarioGalic อธิบายว่าทำไมสิ่งนี้ถึงเกิดขึ้น)

นี่คือสิ่งที่คุณต้องการ:

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)

ในคำตอบอื่น ๆ _.intValueที่ผมแนะนำ ฉันเดาว่ามันจะบันทึกการโทรเพื่อการแปลงเท่านั้น
som-snytt

1

ต้องเผชิญกับปัญหาเดิมมาก่อน พฤติกรรมที่น่าสงสัยนี้เป็นที่รู้จักโดยทีมงานสกาล่า ดูเหมือนว่าการเปลี่ยนแปลงมันจะทำลายบางสิ่งบางอย่างที่อื่น ดูhttps://github.com/scala/bug/issues/11236และhttps://github.com/scala/scala/pull/5176


2
พฤติกรรมที่น่าสงสัยจริงๆคือปฏิบัติต่อnullเป็นจำนวนเต็ม นี่อาจเป็นอาการเมาค้างจากการCที่มันตกลงเพื่อกำหนด0ให้ตัวชี้ แต่นี่ไม่ได้หมายความว่าตัวชี้ส่งผลให้เป็นดังนั้นจึงเป็นที่หลบสลับไปมาระหว่างทั้งสองแม้จะอยู่ใน0 C
ทิม

Integerส่วนใหญ่อาจมาจากรหัส Java ดังนั้น 'อย่าปฏิบัติต่อ null เนื่องจากจำนวนเต็ม' ไม่ใช่คำแนะนำที่สามารถดำเนินการได้ และเราอย่างชัดเจนตรวจสอบจำนวนเต็มนี้ nullability Option.applyใช้ ดังนั้นเราจึงได้ผลลัพธ์ที่ไม่คาดคิดโดยไม่มีการดำเนินการใด ๆ ที่ไม่ปลอดภัย
simpadjo

ประเด็นคือคุณไม่สามารถตำหนิ Scala สำหรับ "พฤติกรรมที่น่าสงสัย" เมื่อสาเหตุที่แท้จริงคือ Java คำแนะนำที่สามารถดำเนินการได้คือการแปลงอย่างชัดเจนจากประเภท Java เป็นประเภท Scala ที่เทียบเท่าแทนที่จะใช้การแปลงโดยนัย (ดังนั้นจึงJavaConvertersมากกว่าJavaConversion)
ทิม

1
ดีฉันสามารถและฉันจะตำหนิสกาล่าที่ไม่ปล่อยข้อผิดพลาดการรวบรวม / คำเตือนในกรณีนี้ แม้ความผิดพลาดรันไทม์จะดีกว่า แม้แต่ใน บริษัท ของฉันเพียงผู้เดียว 2 นักพัฒนาที่มีประสบการณ์มากกว่า 5 ปีในสกาล่าก็ประสบปัญหานี้
simpadjo

1
@ Tim theInteger.intValue()มันจะเป็นเรื่องง่ายมากที่จะได้รับความผิดพลาดรันไทม์โดยเพียงแค่การเรียกร้อง การหลีกเลี่ยงความผิดพลาดนั้นคือค่าใช้จ่ายในการตรวจสอบรันไทม์พิเศษ ในรุ่นเก่าของ Scala การแปลงนี้ทำให้เกิด NPE อย่างแน่นอน มันถูกรายงานว่าเป็นข้อบกพร่องและจับจ้องไปที่พฤติกรรมปัจจุบัน ฉันไม่ใช่ผู้เชี่ยวชาญ Scala แต่ฉันขุดscala-dev # 355และscala # 5176เป็นบริบททางประวัติศาสตร์
amalloy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.