嵌套Scala选项字段的最佳实践?

时间:2015-02-20 10:07:28

标签: scala scala-option

我有很多嵌套对象,都包含在Scala Option类型中。在我的项目的其他地方,我不得不调用一个嵌入了5级深度的属性(其中一些是列表),每次调用.get。这样我最终会看到如下内容:

objectA.get.attrB.get.attrC.get(0).attrD.get

除了一系列.get调用(我不确定是理想的)之外,我没有用这种方式实现很多错误处理,如果任何属性都是空的,那么整个事情就会崩溃。给定嵌套调用,如果我将其限制为如上所述的单行,我最后也只能使用.getOrElse一次。

Scala中是否有任何建议的使用Option类型的方法?

2 个答案:

答案 0 :(得分:6)

在这种情况下,开箱即用的最易读的解决方案(即没有编写帮助方法)可能会将调用链接到Option.flatMap

objectA flatMap (_.attrB) flatMap (_.attrC.headOption) flatMap (_.attrD)

使用flatMap,如果链中的任何选项为None,您最终会以None结尾(与{{1不同)在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) (因为理解被贬低到flatMap / flatMap的链),但在这种情况下它实际上会更不易读(相反通常是正确的)因为在每一步中你都必须引入一个绑定,然后在下一步中引用它:

map

如果您愿意使用ScalaZ,另一种解决方案是使用for ( a <- objectA; b <- a.attrB; c <- b.attrC.headOption; d <- c.attrD ) yield d 代替>>=,这会缩短一些时间:

flatMap

这与使用val objectA = Option(A(Some(B(List(C(Some("foo")), C(Some("bar"))))))) // returns Some(foo) objectA >>= (_.attrB) >>= (_.attrC.headOption) >>= (_.attrD) 完全相同,只是更短。

答案 1 :(得分:2)

我相信你想要这个,

val deepNestedVal = objectA.get.attrB.get.attrC.get.attrD.get

我认为更优选的方式是使用for -reherehe,

val deepNestedVal = for {
  val1 <- objectA
  val2 <- val1.attrB
  val3 <- val2.attrC
  val4 <- val3.attrD
} yield val4

其他方式是使用flatMap,如@RégisJean-Gilles的回答所示