使用Scala中的默认值更新可变映射

时间:2013-01-30 13:15:19

标签: scala map

考虑以下代码,计算列表中每个字符串的频率,并将结果存储在可变映射中。这很好用,但我不明白+ =方法的定义在哪里?!这是一些奇怪的隐式转换事物还是什么?我在某处看到了这段代码,但它没有包含对+ =。

的解释
val list = List("a", "b", "a")
val counts = new scala.collection.mutable.HashMap[String, Int]().withDefaultValue(0)
list.foreach(counts(_) += 1)
counts
//> res7: scala.collection.mutable.Map[String,Int] = Map(a -> 2, b -> 1)

map的apply会返回一个Int,但是Int没有+ =并且这个方法用一个新值更新map,所以看起来apply会返回一个带有+ =方法的可变整数。

2 个答案:

答案 0 :(得分:8)

这不是隐含的转换 - 它是一种贬义。 写作:

x += 1
去往:

x = x + 1

如果x的类没有定义+=方法。

以同样的方式:

counts("a") += 1
去往:

counts("a") = counts("a") + 1

因为counts("a")Int,而Int没有定义+=方法。

另一方面,写作:

x(expression1) = expression2

在Scala中调用update方法:

x.update(expression1, expression2)

每个可变Map都有一个update方法defined - 它允许在地图中设置关键字。

所以整个表达都被贬低了:

list.foreach(x => counts.update(x, counts(x) + 1))

不要将此+=与Scala中+=的{​​{1}}方法混淆。如果该密钥已存在,则该方法更新映射中的条目,或者添加新的键值对。它返回mutable.Map引用,即相同的地图,因此您可以链接this个调用。请参阅ScalaDocsource code

答案 1 :(得分:3)

对于您想知道代码的一部分中发生了什么编译魔术的时刻,scalac -print是您最好的朋友(请参阅this question)。

如果您执行C.scala

scalac -print C.scala
package test

class C {
    def myMethod() {
        val counts = new scala.collection.mutable.HashMap[String, Int]().withDefaultValue(0)
        counts("a") += 1
    }
}

你得到了

package test {
  class C extends Object {
    def myMethod(): Unit = {
      val counts: collection.mutable.Map = new collection.mutable.HashMap().withDefaultValue(scala.Int.box(0));
      counts.update("a", scala.Int.box(scala.Int.unbox(counts.apply("a")).+(1)))
    };
    def <init>(): test.C = {
      C.super.<init>();
      ()
    }
  }

对我来说也是一个惊喜,但显然scalac会改变

map(key) =<op> rhs

map.update(key, map.apply(key) <op> rhs)