另一个 Option 对象内的 Scala Option 对象

标签 scala option monads scalaz

我有一个模型,它有一些 Option 字段,其中包含另一个 Option 字段。例如:

case class First(second: Option[Second], name: Option[String])
case class Second(third: Option[Third], title: Option[String])
case class Third(numberOfSmth: Option[Int])

我从外部 JSON 接收这些数据,有时这些数据可能包含空值,这就是这种模型设计的原因。

所以问题是:获得最深场的最佳方法是什么?
First.get.second.get.third.get.numberOfSmth.get

上面的方法看起来非常难看,如果其中一个对象为 None,则可能会导致异常。我正在寻找 Scalaz lib,但没有想出更好的方法来做到这一点。

有任何想法吗?
提前致谢。

最佳答案

解决方法是使用Option.mapOption.flatMap :

First.flatMap(_.second.flatMap(_.third.map(_.numberOfSmth)))

或等效的(请参阅本答案末尾的 更新 ):
First flatMap(_.second) flatMap(_.third) map(_.numberOfSmth)

这将返回 Option[Int] (前提是 numberOfSmth 返回 Int )。如果调用链中的任何选项是 None ,结果将是 None , 否则为 Some(count)哪里countnumberOfSmth 返回的值.

当然,这会很快变得丑陋。出于这个原因,scala 支持将理解作为一种语法糖。以上可以改写为:
for { 
  first <- First
  second <- first .second
  third <- second.third
} third.numberOfSmth

这可以说更好(特别是如果您还不习惯在任何地方看到 map/flatMap,使用 scala 一段时间后肯定会出现这种情况),并在引擎盖下生成完全相同的代码。

有关更多背景信息,您可以查看另一个问题:What is Scala's yield?

更新 :
感谢 Ben James 指出 flatMap 是关联的。换句话说 x flatMap(y flatMap z)))x flatMap y flatMap z 相同.虽然后者通常不会更短,但它具有避免任何嵌套的优点,这更容易遵循。

这是 REPL 中的一些说明(4 种样式是等效的,前两种使用 flatMap 嵌套,其他两种使用 flatMap 的扁平链):
scala> val l = Some(1,Some(2,Some(3,"aze")))
l: Some[(Int, Some[(Int, Some[(Int, String)])])] = Some((1,Some((2,Some((3,aze))))))
scala> l.flatMap(_._2.flatMap(_._2.map(_._2)))
res22: Option[String] = Some(aze)
scala> l flatMap(_._2 flatMap(_._2 map(_._2)))
res23: Option[String] = Some(aze)
scala> l flatMap(_._2) flatMap(_._2) map(_._2)
res24: Option[String] = Some(aze)
scala> l.flatMap(_._2).flatMap(_._2).map(_._2)
res25: Option[String] = Some(aze)

关于另一个 Option 对象内的 Scala Option 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15111565/

相关文章:

Scalaz 验证 : aggregate errors or return any success

scala - 绕过 Spark (Scala) 中每个文件的第一行

scala - Akka 路由 : Reply's send to router ends up as dead letters

ruby-on-rails - 如何选择f.select rails

scala - 添加reactivemongo后出现错误 "play-iteratees_2.10 not found"

java - 如何将环境变量传递给jar文件?

scala - 如何编写 "orElse"的惰性可变参数版本

Haskell 处理 [IO 字符串]

Haskell:对 `>>=` 运算符的类型感到困惑

scala - 应用仿函数如何与并行算法联系起来? (斯卡拉和斯卡拉兹)