Почему Некоторые (ноль) не считаются Нет? - PullRequest
35 голосов
/ 27 апреля 2011

Мне любопытно:

scala> Some(null) == None
res10: Boolean = false

Почему Some(null) не преобразовано в None?

Ответы [ 6 ]

56 голосов
/ 27 апреля 2011

Вы должны использовать Option(null) для достижения желаемого эффекта и возврата None.

Some(null) просто создает новый Option с определенным значением (отсюда Some), которое на самом деле null, и есть несколько веских причин, чтобы когда-либо создавать подобное в реальном коде.

27 голосов
/ 27 апреля 2011

К сожалению, null является допустимым значением для любого типа AnyRef, что является следствием взаимодействия Scala с Java. Таким образом, метод, который принимает объект типа A и внутренне хранит его внутри Option, вполне может потребовать хранения null внутри этой опции.

Например, допустим, у вас есть метод, который берет заголовок списка, проверяет, соответствует ли этот заголовок ключу в хранилище, а затем возвращает true, если это так. Можно реализовать это так:

def isFirstAcceptable(list: List[String], keys: Set[String]): Boolean =
    list.headOption map keys getOrElse false

Итак, вот в чем дело ... если то, что внутри list и keys происходит от какого-то Java API, они оба могут содержать null! Если Some(null) невозможно, то isFirstAcceptable(List[String](null), Set[String](null)) вернет false вместо true.

12 голосов
/ 10 июля 2012

Я думаю, что остальные в цепочке хорошо объясняют, почему Some(null) "должен" существовать, но если вам случается получить Some(null) где-то и вы хотите быстрый способ превратить его в None, я ' мы делали это раньше:

scala> val x: Option[String] = Some(null)
x: Option[String] = Some(null)

scala> x.flatMap(Option(_))
res8: Option[String] = None

И когда начальный Option является допустимым ненулевым значением, все работает так, как вы, вероятно, хотите:

scala> val y: Option[String] = Some("asdf")
y: Option[String] = Some(asdf)

scala> y.flatMap(Option(_))
res9: Option[String] = Some(asdf)
12 голосов
/ 27 апреля 2011

Большая часть WTF Scala может быть объяснена необходимостью совместимости с Java.null часто используется в Java в качестве значения, указывая, возможно, на отсутствие значения.Например, hashMap.get(key) вернет null, если ключ не сопоставлен.

Имея это в виду, рассмотрите следующие возможные значения при переносе нулевого метода возврата в Option:

if (b) Some(hashMap.get(key)) else None
// becomes -->
None // the method was not invoked;
Some(value) // the method was invoked and a value returned; or
Some(null) // the method was invoked and null was returned.

Some(null) кажется достаточно отличным от None в этом случае, чтобы оправдать его разрешение на языке.

Конечно, если это нежелательно в вашем случае, тогда просто используйте:

if (b) Option(hashMap.get(key)) else None
// becomes -->
None // the method was not invoked or the mapped value was null; or
Some(value) // the method was invoked and a value returned
2 голосов
/ 27 апреля 2011

В качестве простого мысленного эксперимента рассмотрим два списка строк, один из которых имеет длину 5, а другой - длину 20.

Поскольку мы работаем на JVM, можно вставить null в качестве допустимогоэлемент в один из этих списков - поэтому поместите его в длинный список как элемент # 10

В чем же тогда разница между значениями, возвращаемыми из двух следующих выражений?

РЕДАКТИРОВАТЬ: Обмен get на lift, я думал о картах ...

shortList.lift(10) //this element doesn't exist
longList.lift(10)  //this element exists, and contains null
1 голос
/ 20 августа 2017

Потому что Option считается Функтором, а быть Функтором означает:

  1. Имеет функцию unit (apply или просто Option("blah") в Scala)
  2. Имеет map функцию, которая преобразует значение из T=>B, но не из контекста
  3. Слушается 2 закона Функтора - закон тождества и ассоциативный закон

В этой теме основная часть # 2 - Option(1).map(t=>null) не может преобразовать контекст. Some должно остаться. Иначе это тормозит ассоциативный закон!

Просто рассмотрим следующий пример законов:

def identity[T](v: T) = v
def f1(v: String) = v.toUpperCase
def f2(v: String) = v + v
def fNull(v: String): String = null

val opt = Option("hello")

//identity law
opt.map(identity) == opt //Some(hello) == Some(hello)

//associative law
opt.map(f1 _ andThen f2) == opt.map(f1).map(f2) //Some(HELLOHELLO) == Some(HELLOHELLO)
opt.map(fNull _ andThen f2) == opt.map(fNull).map(f2) //Some(nullnull) == Some(nullnull)

Но что, если Option("hello").map(t=>null) произвел None? Ассоциативный закон будет нарушен:

opt.map(fNull _ andThen f2) == opt.map(fNull).map(f2) //Some(nullnull) != None

Это моя мысль, может быть неправильно

...