Option.map(空)returns一些(空)

Option.map (null) returns Some (null)

我想要这个代码片段 return 我 None 而不是 Some(null):

Option(x).map(x.getNullValue) // returns Some(null)

我听说 Scalaz 库有处理这种情况的功能。那么如何使用 scalaz 和标准 Scala 库来实现我的目标呢?

您可以在此处将 flatMapOption.apply 方法一起使用,而不是引入 scalaz:

Option(initialValue).flatMap(x => Option(x.getNullValue))

这是有效的,因为 Option.apply 方法智能地执行 null

val x: String = null
Option(x) //None
Option("foo") //Some("foo")

所以如果你完全知道这个值,你可以简单地做:

Option(x.getNullValue)

您还可以在 Option 上使用其他方法,例如 filterorElsegetOrElse,视情况而定:

Option(initialValue).map(_.getNullValue).filter(_ != null)
Option(initialValue).orElse(Option(x.getNullValue))
Option(x.getNullValue).getOrElse(defaultValue)

我不知道 scalaz,但在标准库中,您唯一的选择确实是过滤掉 null 值。 map 只是映射 A => B 并期望 B 不会是 null.

示例:

object HasNull {
    def getNull: Any = null
}

scala> Option(HasNull).map(_.getNull).filter(_ != null)
res24: Option[Any] = None

或者

scala> Option(HasNull).flatMap(a => Option(a.getNull))
res25: Option[Any] = None

或者,您可以使用一些隐含的魔法来避免 Option 样板文件:

implicit def toOpt[A](a: A): Option[A] = Option(a)

scala> Option(HasNull).flatMap(_.getNull)
res3: Option[Any] = None

使用 flatMap 仍然是关键,因为它需要一个 Option[B]。但是 getNullB 类型,因此将使用隐式转换,这会将 nullable 再次包装在 Option.apply 中。

正如其他人已经写过的那样,您可以使用 flatMap 来完成。一个非常相似的方法是:

case class User(name: String)
val users = List(null, User("John"), User(null))
for{
  userDb <- users
  user <- Option(userDb)
  name <- Option(user.name)
} yield name

None 的问题是您不知道得到的是哪个 None:用户不存在或名称?在这种情况下,scalaz 可以帮助您:

for{
  userDb <- users
  user <- Option(userDb) \/> "No user found."
  name <- Option(user.name) \/> "No name provided."
} yield name

但这是另外一回事了。你可以找到关于这个用例的精彩解释 here (video).