Варіант Scala (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
Про це нещодавно запитали десь, тож справжній гатч. Можливо, проблема покладається на умовивід: Option[Integer](i).map(_.intValue)мені здається найбільш ідіоматичним, оскільки він говорить про те, що робить. Також використовуйте, -Xlintщоб побачити попередження для val o!
som-snytt

Щоб уникнути прямого боксу, `val x: Option [Int] = Option (i) .asInstanceOf [Option [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

З тією ж проблемою стикалися і раніше. Ця сумнівна поведінка відома команді Scala. Здається, що його зміна порушує щось інше. Дивіться https://github.com/scala/bug/isissue/11236 та https://github.com/scala/scala/pull/5176 .


2
Дійсно сумнівна поведінка трактується nullяк ціле число. Це, мабуть, похмілля, Cзвідки добре призначити 0покажчик. Але це не означає, що отриманий вказівник є 0, тому перемикатися між двома навіть в C.
Тім

Integerнайімовірніше, походить з коду Java, тому "не ставитись до нуля як до цілого числа" не є корисною порадою. І ми чітко перевіряємо цей цілий інтерес на предмет зменшення за допомогою Option.apply. Таким чином, ми отримуємо несподіваний вихід без явного виконання будь-яких небезпечних операцій.
simpadjo

Справа в тому, що ви не можете звинувачувати Scala у «сумнівній поведінці», коли першопричиною є Java. Діяльна порада полягає в явному перетворенні з типів Java в еквівалентні типи Scala, а не використовувати неявну конверсію. (Отже, JavaConvertersа не JavaConversion)
Тім

1
Що ж, я можу і я звинувачую Scala в тому, що в цій справі не видається помилка компіляції / попередження. Навіть крах часу виконання буде кращим. Навіть лише в моїй компанії 2 проблеми з Scala винищили цю розробку із 5+-річним досвідом роботи.
simpadjo

1
@Tim Це було б дуже легко отримати аварійний процес, просто зателефонувавши theInteger.intValue(). Уникнення краху - це те, що коштує додаткової перевірки часу виконання. У старих версіях Scala ця конверсія справді створювала NPE; це повідомлялося про помилку та виправлялось на поточну поведінку. Я не експерт Scala, але я розкопав scala-dev # 355 та scala # 5176 як історичний контекст.
amalloy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.