Gro*_*lla 3 scala scala-option
我有许多嵌套对象,所有嵌套对象都包含在Scala Option类型中.在我的项目的其他地方,我不得不调用一个嵌入了5级深度的属性(其中一些是列表),每次调用.get.这样我最终得到的东西如下所示:
objectA.get.attrB.get.attrC.get(0).attrD.get
Run Code Online (Sandbox Code Playgroud)
除了一系列.get调用(我不确定是理想的)之外,我没有以这种方式实现很多错误处理,如果任何属性都是空的,那么整个事情就会崩溃.鉴于嵌套调用,如果我将其限制为如上所述的单行,我也只能.getOrElse在最后使用一次.
是否有任何建议的方法在Scala中使用Option类型?
在这种情况下,开箱即用的最易读的解决方案(也就是说,没有编写帮助器方法)可能会将调用链接到Option.flatMap:
objectA flatMap (_.attrB) flatMap (_.attrC.headOption) flatMap (_.attrD)
Run Code Online (Sandbox Code Playgroud)
通过使用flatMap,如果链中的任何选项是None,你最终会None得到结果(没有例外,与get被调用的时候不同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)
Run Code Online (Sandbox Code Playgroud)
你也可以用于理解而不是flatMap(因为理解被贬低到flatMap/的链map),但在这种情况下它实际上会更不可读(相反通常是正确的),因为在每一步你必须引入一个绑定然后参考下一步:
for ( a <- objectA; b <- a.attrB; c <- b.attrC.headOption; d <- c.attrD ) yield d
Run Code Online (Sandbox Code Playgroud)
如果您愿意使用ScalaZ,另一个解决方案是使用它>>=来代替flatMap,这会使它更短:
val objectA = Option(A(Some(B(List(C(Some("foo")), C(Some("bar")))))))
// returns Some(foo)
objectA >>= (_.attrB) >>= (_.attrC.headOption) >>= (_.attrD)
Run Code Online (Sandbox Code Playgroud)
这与使用完全一样flatMap,只是更短.