为了理解 Option 数组

For comprehension over Option array

我遇到编译错误:

Error:(64, 9) type mismatch;
 found   : Array[(String, String)]
 required: Option[?]
      y <- x
        ^

片段中:

val z = Some(Array("a"->"b", "c" -> "d"))
val l = for(
  x <- z;
  y <- x
) yield y

为什么数组生成器不生成数组项? Option 的要求来自哪里?

更荒谬的是,如果我用 println(y) 替换 "yield" 那么它确实可以编译。

Scala 版本:2.10.6

这是通常的 "option must be converted to mix monads" 事情。

scala> for (x <- Option.option2Iterable(Some(List(1,2,3))); y <- x) yield y
res0: Iterable[Int] = List(1, 2, 3)

比较

scala> for (x <- Some(List(1,2,3)); y <- x) yield y
<console>:12: error: type mismatch;
 found   : List[Int]
 required: Option[?]
       for (x <- Some(List(1,2,3)); y <- x) yield y
                                      ^

scala> Some(List(1,2,3)) flatMap (is => is map (i => i))
<console>:12: error: type mismatch;
 found   : List[Int]
 required: Option[?]
       Some(List(1,2,3)) flatMap (is => is map (i => i))
                                           ^

scala> for (x <- Some(List(1,2,3)).toSeq; y <- x) yield y
res3: Seq[Int] = List(1, 2, 3)

这是因为 for 表达式被翻译成 mapflatmapforeach 表达式的方式。让我们首先简化您的示例:

val someArray: Some[Array[Int]] = Some(Array(1, 2, 3))
val l = for {
  array: Array[Int] <- someArray
  number: Int <- array
} yield number

按照Scala language specification的相关部分,先翻译成

someArray.flatMap {case array => for (number <- array) yield number}

这又被翻译成

someArray.flatMap {case array => array.map{case number => number}}

问题是 someArray.flatMap 需要从 Array[Int]Option[Array[Int]] 的函数,而我们提供了从 Array[Int]Array[Int] 的函数。

如果将 yield number 替换为 println(number),则编译错误消失的原因是 for 循环与 for comprehensions 的翻译不同:它现在将被翻译为 someArray.foreach{case array => array.foreach {case item => println(item)}},这没有相同的打字问题。

一种可能的解决方案是首先将 Option 转换为您希望最终得到的集合类型,以便其 flatMap 方法具有正确的签名:

val l = for {
  array: Array[Int] <- someArray.toArray
  number: Int <- array
} yield number