解决方案是使用Option.map
and Option.flatMap
:
First.flatMap(_.second.flatMap(_.third.map(_.numberOfSmth)))
或等价物(请参阅此答案末尾的更新):
First flatMap(_.second) flatMap(_.third) map(_.numberOfSmth)
这将返回一个Option[Int]
(前提是numberOfSmth
返回一个Int
)。如果调用链中的任何选项是None
,则结果将是None
,否则它将是Some(count)
wherecount
的返回值numberOfSmth
。
当然,这会很快变得丑陋。出于这个原因,scala 支持将理解作为语法糖。上式可以改写为:
for {
first <- First
second <- first .second
third <- second.third
} third.numberOfSmth
可以说哪个更好(特别是如果您还不习惯在任何地方看到map
/ flatMap
,使用 scala 一段时间后肯定会出现这种情况),并在引擎盖下生成完全相同的代码。
有关更多背景信息,您可以查看另一个问题:Scala 的产量是多少?
更新:感谢 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)