web-dev-qa-db-ja.com

Some(null)がNoneと見なされないのはなぜですか?

気になります:

_scala> Some(null) == None
res10: Boolean = false
_

Some(null)Noneに変換されないのはなぜですか?

36
Geo

Option(null)を使用して目的の効果を達成し、Noneを返す必要があります。

Some(null)は定義された値(したがってOption)で新しいSomeを作成するだけで、実際にはnullであり、作成する正当な理由はほとんどありません。実際のコードではこのように。

57

残念ながら、nullは、任意のAnyRefタイプに対して有効な値です。これは、ScalaとJavaの相互運用性の結果です。したがって、タイプAのオブジェクトを受け取り、それを内部的にOption内に格納するメソッドは、そのオプション内にnullを格納する必要があるかもしれません。

たとえば、リストの先頭を取得し、その先頭がストア内のキーに対応しているかどうかを確認し、対応している場合はtrueを返すメソッドがあるとします。このように実装するかもしれません:

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

だから、これが...listkeysの内部がいくつかのJava APIから来ている場合、両方にnullが含まれている可能性があります!Some(null)が不可能な場合は、isFirstAcceptable(List[String](null), Set[String](null))は、falseの代わりにtrueを返します。

27

スレッドの他のメンバーは、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が正当なnull以外の値である場合、おそらく期待どおりに機能します。

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

scala> y.flatMap(Option(_))
res9: Option[String] = Some(asdf)
13
overthink

ScalaのWTFの多くは、Javaとの互換性の必要性に起因する可能性があります。 nullは、Javaで値として使用されることが多く、おそらく値がないことを示します。たとえば、hashMap.get(key)nullを返します。キーが一致しない場合。

これを念頭に置いて、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
_
13
Synesso

オプションはファンクターと見なされ、ファンクターであるということは次のことを意味します。

  1. unit関数があります(Scalaではapplyまたは単にOption("blah")
  2. 値を_T=>B_から変換するmap関数がありますが、コンテキストはありません
  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
_

それは私の考えです、間違っているかもしれません

2
Eugene Zhulkov

簡単な思考実験として、長さ5と長さ20の2つの文字列リストを考えてみましょう。

JVMで実行しているため、これらのリストの1つに有効な要素としてnullを挿入することができます。したがって、それを要素#10として長いリストに入れます。

では、次の2つの式から返される値の違いは何でしょうか。

EDIT:getliftに交換しました、私は地図を考えていました...

shortList.lift(10) //this element doesn't exist
longList.lift(10)  //this element exists, and contains null
2
Kevin Wright