Scala - 从 Map 到 Iterable 的意外类型切换以进行理解?
Scala - unexpected type switch from Map to Iterable in 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))
为什么会这样?
如果你运行scala -Xprint:typer -e "for { ... } yield k->v"
,你可以获得代码的脱糖版本。这是你得到的非常的简化版本:
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)
}
所以您会注意到,当 for-comprehension 转换为 .map
调用时,它实际上是 returning foo
和 bar
以及k->v
,这意味着它是一个 Tuple3[(Int,Int), Int, Int]
。由于 Tuple3
对象的可迭代不能变成 Map
,它假定它必须 return 和 Iterable
。但是,为了获得正确的输出,即 Tuple2
对象的集合,它执行了次级 .map
,从 [=18= 中丢弃了 foo
和 bar
],但此时它不再知道它应该是 Map
,因为当您链式调用 .map
时,该信息不会被传递。
你只有一个赋值的例子很幸运,因为中间表示是 Tuple2[(Int,Int), Int]
.
另一方面,如果您直接使用 .map
,它会起作用:
Map(0->1, 2->3).map {
case (k,v) =>
val foo = 1
val bar = 2
k -> v
}
我对在幕后为理解地图而进行的打字感到困惑。我的理解是通常应该保留外部集合类型,我们在以下两种情况下看到了预期的行为:
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))
为什么会这样?
如果你运行scala -Xprint:typer -e "for { ... } yield k->v"
,你可以获得代码的脱糖版本。这是你得到的非常的简化版本:
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)
}
所以您会注意到,当 for-comprehension 转换为 .map
调用时,它实际上是 returning foo
和 bar
以及k->v
,这意味着它是一个 Tuple3[(Int,Int), Int, Int]
。由于 Tuple3
对象的可迭代不能变成 Map
,它假定它必须 return 和 Iterable
。但是,为了获得正确的输出,即 Tuple2
对象的集合,它执行了次级 .map
,从 [=18= 中丢弃了 foo
和 bar
],但此时它不再知道它应该是 Map
,因为当您链式调用 .map
时,该信息不会被传递。
你只有一个赋值的例子很幸运,因为中间表示是 Tuple2[(Int,Int), Int]
.
另一方面,如果您直接使用 .map
,它会起作用:
Map(0->1, 2->3).map {
case (k,v) =>
val foo = 1
val bar = 2
k -> v
}