for-comprehension returns None 如果 `for` 中的至少一个组件是 None

for-comprehension returns None if at least one component in `for` is None

我很难理解在 Scala 中使用 for-compression 的机制。 例如,如果我有

val x = for {
  i <- Option(1)
  j <- Option(2)
  k <- Option(3)
} yield (i,j,k)

xx: Option[(Int, Int, Int)] = Some((1,2,3))。 但是,如果至少有一个组件是 None,例如

val x = for {
  i <- Option(1)
  j <- Option(2)
  k <- None
} yield (i,j,k)

那么 x 就是 x: Option[(Int, Int, Nothing)] = None,而我实际上希望看到类似这样的内容:x: Option[(Int, Int, Nothing)] = Some((1,2,None)).

我查看了FAQ from Scala official documentation,其中明确指出for-comprehensionflatmapmap的组合。但是我还是很难理解 xNone.

我想我错过了一些关于 flatmapmap 区别的重要概念。

第for-comprehension"desugars"转成:

val x = Option(1).flatMap(
  i => Option(2).flatMap(
    j => Option(3).map(
      k => (i, j, k)
    )
  )
)

如您所见 - 第一个选项是 flat-mapped 使用一个取其值的函数(如果它存在)和 returns 一个三元组(在第二个选项上使用类似的操作) .不管那个函数是什么——整个表达式的形式是:

val x = Option(1).flatMap(f)

现在,如果我们将 Option(1) 替换为 None(就像您在第二个表达式中所做的那样),我们显然会得到 None:

val x = None.flatMap(f) // None, for any f

您期望的结果 (Some((None, 2, 3))) 不太有用 - 因为对于不同的输入,它会有 不同的类型 :它会是 (Option[Int], Int, Int) ?还是(Int, Int, Int)?还是(Option[Int], Option[Int], Option[Int])(None, 2, 3)(1, None, 3)(1, 2, None) 唯一常见的类型是 not-so-useful (Any, Any, Any).