Опция Scala (null) ожидается как None, но я получил Some (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!
Сом-Снитт
Чтобы избежать обхода в боксе, `val x: Option [Int] = Option (i) .asInstanceOf [Option [Int]]` где Integerвыводится.
Сом-Снитт
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. Я думаю, это только сохраняет конверсионный звонок.
Сом-Снитт
1

Столкнулся с той же проблемой раньше. Это сомнительное поведение известно команде Scala. Кажется, что изменение его ломает что-то в другом месте. См. Https://github.com/scala/bug/issues/11236 и https://github.com/scala/scala/pull/5176 .

simpadjo
источник
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 как исторический контекст.
Амаллой