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

Best Practices for nested Scala Option fields?

我有许多嵌套对象,全部包含在 Scala Option 类型中。在我的项目的其他地方,每次调用 .get 时,我都必须调用一个嵌入大约 5 层深的属性(其中一些是列表)。这样我最终得到如下所示的内容:

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

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

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

在这种情况下,开箱即用的最易读的解决方案(即不编写辅助方法)可以说是链式调用 Option.flatMap:

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

通过使用 flatMap,如果链中的任何选项是 None,您最终会得到 None(与 [=18 不同,没有例外) =] 在 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 comprehensions 而不是 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)

这与使用 flatMap 完全一样,只是更短。

我相信你想要这个,

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

我认为更可取的方式是使用 for-comprehension,

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

其他方法是使用 flatMap,如@Régis Jean-Gilles

的回答所示