Мне любопытно:
scala> Some(null) == None
res10: Boolean = false
Почему Some(null)
не преобразован в None
?
Мне любопытно:
scala> Some(null) == None
res10: Boolean = false
Почему Some(null)
не преобразован в None
?
Вы должны использовать Option(null)
для достижения желаемого эффекта и возврата None
.
Some(null)
просто создает новый Option
с определенным значением (следовательно, Some
), который на самом деле null
, и есть несколько веских причин когда-либо создавать такой код в реальном коде.
К сожалению, 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
.
Большая часть Scala WTFs может быть отнесена к его потребности в совместимости с 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
Я думаю, что другие в потоке хорошо справляются, объясняя, почему 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)
В качестве простого мысленного эксперимента рассмотрим два списка строк, один из которых длиной 5 и один длиной 20.
Поскольку мы работаем на JVM, можно вставить null
в качестве допустимого элемента в один из этих списков - поэтому поставьте это в длинном списке как элемент # 10
В чем же разница в значениях, возвращаемых из двух следующих выражений?
EDIT: Обмен get
для lift
, я думал о картах...
shortList.lift(10) //this element doesn't exist
longList.lift(10) //this element exists, and contains null
Поскольку Опция считается Функтором и является Функтором, значит:
unit
(apply
или просто Option("blah")
в Scala)map
, которая преобразует значение из T=>B
, но не контекстВ этом разделе основная часть # 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
Это моя мысль, может быть неправильно