Tùy chọn Scala (null) được mong đợi là Không nhưng tôi đã nhận được Một số (0)


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

Cách an toàn để chuyển đổi null: java.lang.Integersang Scala là Option[Int]gì?


1
Bạn có thể vui lòng dán mã của bạn trong câu hỏi?
Hồi giáo

Câu trả lời:


17

Bạn đang pha trộn Intjava.lang.Integervì vậy

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

ngầm chuyển sang

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

trở thành

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

do đó

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

Nếu bạn muốn làm việc với java.lang.Integer, sau đó viết

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

2
Điều này gần đây đã được hỏi ở đâu đó, vì vậy nó là một gotcha thực sự. Có lẽ vấn đề đang dựa vào suy luận: Option[Integer](i).map(_.intValue)dường như là thành ngữ nhất đối với tôi, vì nó nói những gì nó đang làm. Ngoài ra, sử dụng -Xlintđể xem cảnh báo cho val o!
som-snytt

Để tránh vòng đấu quyền anh, `val x: Option [Int] = Option (i) .asInstanceOf [Option [Int]]` nơi Integerđược suy ra.
som-snytt

7

Điều này dường như đang xảy ra bởi vì bạn đang tạo Optionvà chuyển đổi nó thành một Intbước ( câu trả lời của @ MarioGalic giải thích lý do tại sao điều này xảy ra).

Đây là những gì bạn muốn:

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)

Về câu trả lời khác, tôi đề nghị _.intValue. Tôi đoán nó chỉ lưu cuộc gọi chuyển đổi.
som-snytt

1

Đối mặt với vấn đề tương tự trước đây. Hành vi đáng ngờ này được biết đến bởi nhóm Scala. Có vẻ như thay đổi nó phá vỡ một cái gì đó ở nơi khác. Xem https://github.com/scala/orms/issues/11236https://github.com/scala/scala/pull/5176 .


2
Các hành vi thực sự nghi vấn là đối xử nullnhư một số nguyên. Đây có lẽ là một sự nôn nao từ Cnơi có thể gán 0cho một con trỏ. Nhưng điều này không có nghĩa là con trỏ kết quả là 0, vì vậy thật khó để chuyển đổi giữa hai con trỏ ngay cả trong C.
Tim

Integerrất có thể đến từ mã Java vì vậy 'đừng coi null là số nguyên' không phải là một lời khuyên hữu dụng. Và chúng tôi kiểm tra rõ ràng số nguyên này để biết tính vô hiệu bằng cách sử dụng Option.apply. Vì vậy, chúng tôi nhận được đầu ra bất ngờ mà không thực hiện bất kỳ hoạt động không an toàn.
simpadjo

Vấn đề là bạn không thể đổ lỗi cho Scala vì "hành vi đáng ngờ" khi nguyên nhân gốc là Java. Lời khuyên có thể thực hiện được là chuyển đổi rõ ràng từ các loại Java sang các loại Scala tương đương thay vì sử dụng chuyển đổi ngầm định. (Do đó JavaConverterschứ không phải JavaConversion)
Tim

1
Vâng, tôi có thể và tôi đổ lỗi cho Scala vì đã không phát ra lỗi biên dịch / cảnh báo trong trường hợp này. Ngay cả sự cố thời gian chạy sẽ tốt hơn. Ngay cả trong công ty của tôi, chỉ có 2 nhà phát triển với hơn 5 năm kinh nghiệm trong Scala đã gặp phải vấn đề này.
simpadjo

1
@Tim Sẽ rất dễ dàng để có một sự cố thời gian chạy, chỉ bằng cách gọi theInteger.intValue(). Tránh sự cố đó là chi phí kiểm tra thời gian chạy thêm. Trong các phiên bản cũ hơn của Scala, chuyển đổi này thực sự tạo ra một NPE; nó đã được báo cáo là một lỗi và được sửa với hành vi hiện tại. Tôi không phải là chuyên gia về Scala, nhưng tôi đã chọn scala-dev # 355scala # 5176 làm bối cảnh lịch sử.
amalloy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.