了解Option数组

时间:2016-02-10 00:00:20

标签: arrays scala optional for-comprehension

我收到编译错误:

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

为什么generator over Array不会产生数组项?从需求中选择的来源是什么?

更荒谬的是,如果我用println(y)替换“yield”,那么它就会编译。

Scala版本:2.10.6

2 个答案:

答案 0 :(得分:2)

这是通常的“选项必须转换为混合monad”的事情。

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)

答案 1 :(得分:2)

这是因为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需要一个从Option[Array[Int]]Option[Array[Int]]的函数,而我们提供的函数从Array[Int]Array[Int]

如果yield numberprintln(number)替换,则编译错误消失的原因是for循环的翻译方式与理解不同:它现在将被翻译为someArray.foreach{case array => array.foreach {case item => println(item)}},而不是&# 39; t有相同的打字问题。

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

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