【发布时间】:2011-08-13 09:19:09
【问题描述】:
我很好奇:
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,并且几乎没有正当的理由在实际代码中创建这样的值。
【讨论】:
Some(null) 转换为 None。
不幸的是,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。
【讨论】:
null 在 Scala 中根本不应该存在,并且每个 Java 到 Scala 的接口都需要将 Java 类型包装在 Option 中。 (这实际上是一些没有null 的语言,例如Rust,如何提供与具有null 的语言的互操作。)
我认为线程中的其他人很好地解释了为什么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)
【讨论】:
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
【讨论】:
作为一个简单的思想实验,考虑两个字符串列表,一个长度为 5,一个长度为 20。
因为我们在 JVM 上运行,所以可以将 null 作为有效元素插入其中一个列表中 - 所以将其作为元素 #10 放入长列表中
那么,下面两个表达式返回的值应该有什么区别?
编辑:将get 换成lift,我在考虑地图...
shortList.lift(10) //this element doesn't exist
longList.lift(10) //this element exists, and contains null
【讨论】:
shortList(10) 会抛出异常,真的。但这不是我正在做的......
因为 Option 被认为是 Functor,而成为 Functor 意味着:
unit 函数(apply 或仅在 Scala 中为 Option("blah"))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
这是我的想法,可能是错误的
【讨论】: