5

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

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 返回一个具有 += 方法的可变整数......

4

2 回答 2

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方法——它允许在映射中设置键。

所以整个表达式被取消为:

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

这不要与Scala 中的 s方法+=混淆。如果该键已经存在,该方法会更新映射中的条目,或者添加一个新的键值对。它返回引用,即相同的映射,因此您可以链接调用。请参阅ScalaDoc源代码+=mutable.Mapthis+=

于 2013-01-30T13:30:27.997 回答
3

对于那些你想知道代码的一部分中发生了什么编译器魔法的时刻,scalac -print你最好的朋友是(见这个问题)。

如果您执行scalac -print C.scalaC.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)
于 2013-01-30T13:36:52.950 回答