(对我来说)地图上的这种差异令人惊讶吗;s在Scala 2.8.0和2.7.7中的行为是否符合预期?

(对我来说)地图上的这种差异令人惊讶吗;s在Scala 2.8.0和2.7.7中的行为是否符合预期?,scala,map,scala-2.8,Scala,Map,Scala 2.8,在Scala 2.8.0中,如果将一个map()实例映射到一个2元组序列,最终会得到一个映射。当这种情况发生时,具有相同第一个元素的任何2元组都被视为重复的,并且最终只得到最后一个。这与2.7.7中发生的情况不同。通过一个例子,这更容易理解 Scala 2.7.7: scala> val m = Map("a" -> 1, "b" -> 2, "c" -> 3) m: scala.collection.immutable.Map[java.lang.String,Int]

在Scala 2.8.0中,如果将一个map()实例映射到一个2元组序列,最终会得到一个映射。当这种情况发生时,具有相同第一个元素的任何2元组都被视为重复的,并且最终只得到最后一个。这与2.7.7中发生的情况不同。通过一个例子,这更容易理解

Scala 2.7.7:

scala> val m = Map("a" -> 1, "b" -> 2, "c" -> 3)
m: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1, b -> 2, c -> 3)

scala> m.map { case (k, v) => ("foo", v) }
res5: Iterable[(java.lang.String, Int)] = ArrayBuffer((foo,1), (foo,2), (foo,3))
Scala 2.8.0:

scala> val m = Map("a" -> 1, "b" -> 2, "c" -> 3)
m: scala.collection.immutable.Map[java.lang.String,Int] = Map((a,1), (b,2), (c,3))

scala> m.map { case (k, v) => ("foo", v) }
res16: scala.collection.immutable.Map[java.lang.String,Int] = Map((foo,3))
这是预期的吗?是否在某处记录了变更?这似乎是一个合理的想法,但我花了很多时间升级一个依赖旧行为的2.7.7应用程序

更新:


正如Kris Nuttycombe在下面指出的,在提出这个问题之前阅读可能是一个好的开始:)特别是它提到使用编译器标志
-Xmigration
,这在移植时似乎非常有用。

是的,这是预期的行为;事实上,启用这类功能是2.8中collections系统重新设计的一个要点。默认情况下,Scala将在应用map函数时选择最具体的类型;但是,如果您需要iterable(例如,因为您担心通过重复键消除值),最简单的方法可能是在映射上简单地调用toSeq:

scala> val iter = m.toSeq.map { case (k, v) => ("foo", v) }                                  
iter: Seq[(java.lang.String, Int)] = List((foo,1), (foo,2), (foo,3))

就这一点而言,本文对此进行了广泛的讨论:而且(更是如此)这里:

谢谢你的信息,克里斯。我最终完全按照你的建议解决了这个问题。对于从2.7.7移植,你可以通过在调用
m.map
的任何地方都在作用域中使用正确的隐式CanBuildFrom来简化你的工作。或者问题是避免了不需要的CanBuildFrom?我想到了一个另一种方式更难看,但避免了问问题:简单地使它使编译器无法分辨m是一个带cast的映射:scala>m.asInstanceOf[Iterable[(String,Int)]。map{case(k,v)=>((foo,v)}res0:Iterable[(java.lang.String,Int)]=List((foo,1),(foo,2),(foo,3))