Scala - 意外类型从Map切换到Iterable进行理解?

时间:2016-06-05 04:58:11

标签: scala for-comprehension

我对幕后的打字感到困惑,因为他对地图有所了解。我的理解是外部集合类型通常应该保留,我们在以下两种情况下看到预期的行为:

scala> for {
     |   (k,v) <- Map(0->1,2->3)
     | } yield k -> v
res0: scala.collection.immutable.Map[Int,Int] = Map(0 -> 1, 2 -> 3)

scala> for {
     |   (k,v) <- Map(0->1,2->3)
     |   foo = 1
     | } yield k -> v
res1: scala.collection.immutable.Map[Int,Int] = Map(0 -> 1, 2 -> 3)

但是当我在for comprehension中添加第二个作业时,我得到了一些令人惊讶的东西:

scala> for {
     |   (k,v) <- Map(0->1,2->3)
     |   foo = 1
     |   bar = 2
     | } yield k -> v
res2: scala.collection.immutable.Iterable[(Int, Int)] = List((0,1), (2,3))

为什么会这样?

1 个答案:

答案 0 :(得分:5)

如果您运行val m: Map[Int,Int] = Map(0->1, 2->3) m.map { case x @ (k,v) => val foo = 1 val bar = 2 (x, foo, bar) }.map { case ((k,v), foo, bar) => (k, v) } ,则可以获得代码的去糖版本。这是你得到的非常简化版本:

.map

因此,您注意到,当for-comprehension转换为foo来电时,它实际上会返回bark->v以及{ {1}},这意味着它是Tuple3[(Int,Int), Int, Int]。由于Tuple3个对象的可迭代不能转换为Map,因此它假定它必须返回Iterable。但是,为了获得正确的输出(Tuple2个对象的集合),它会执行从.map丢弃foobar的辅助Tuple3 },但此时它不再知道它应该是Map,因为当您将对.map的呼叫链接起来时,信息无法继续发送。

只有一个作业的例子很幸运,因为中间表示是Tuple2[(Int,Int), Int]

另一方面,如果您直接使用.map,则可以:

Map(0->1, 2->3).map { 
  case (k,v) =>
    val foo = 1
    val bar = 2 
    k -> v
}