Option.map(null)返回Some(null)。

7
我希望这个代码片段返回None而不是Some(null)

代码片段:

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

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


2
Option(x.getNullValue)有什么问题吗? - Nikita
1
@ipoteka x 也可能是空的,所以我也将其包装为 Option - WelcomeTo
3个回答

10
您可以使用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)

您还可以根据具体情况使用filter, orElsegetOrElse等其他Option方法:

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

2

我不了解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]。但是getNull的类型是B,所以将使用隐式转换,将可为空值包装在Option.apply中。


1

正如其他人已经写过的那样,您可以使用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:用户不存在还是名称?在这种情况下,scalaz 可以帮助你:
for{
  userDb <- users
  user <- Option(userDb) \/> "No user found."
  name <- Option(user.name) \/> "No name provided."
} yield name

但这是另外一个故事。你可以在这里找到关于这种用例的精彩解释(链接1)视频)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接