在这种情况下,开箱即用的最易读的解决方案(即,不编写辅助方法)可能是链式调用Option.flatMap
:
objectA flatMap (_.attrB) flatMap (_.attrC.headOption) flatMap (_.attrD)
通过使用flatMap
,如果链中的任何选项是None
,您最终会None
得到 (没有例外,不像get
which 在调用时会爆炸None
)。
举例:
case class C(attrD: Option[String])
case class B(attrC: List[C])
case class A(attrB: Option[B])
val objectA = Some(A(Some(B(List(C(Some("foo")), C(Some("bar")))))))
// returns Some(foo)
objectA flatMap (_.attrB) flatMap (_.attrC.headOption) flatMap (_.attrD)
val objectA2 = Some(A(Some(B(List()))))
// returns None
objectA2 flatMap (_.attrB) flatMap (_.attrC.headOption) flatMap (_.attrD)
您也可以使用 for 理解而不是(用于理解被脱糖到/flatMap
的链),但在这种情况下,它实际上可读性较差(通常情况相反),因为在每一步您都必须引入一个绑定,然后在下一步中参考:flatMap
map
for ( a <- objectA; b <- a.attrB; c <- b.attrC.headOption; d <- c.attrD ) yield d
如果您愿意使用 ScalaZ,另一种解决方案是使用>>=
代替flatMap
,这使它更短:
val objectA = Option(A(Some(B(List(C(Some("foo")), C(Some("bar")))))))
// returns Some(foo)
objectA >>= (_.attrB) >>= (_.attrC.headOption) >>= (_.attrD)
这实际上与 using 完全相同flatMap
,只是更短。