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



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

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 的应用返回一个 Int,但 Int 没有 +=,此方法使用新值更新映射,因此看起来 apply 返回一个具有 += 方法的可变整数......

这不是隐式转换 - 它是一种脱糖。写作:

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 中 mutable.Map s 上的 += 方法混淆。该方法更新映射中的条目(如果该键已存在),或添加新的键值对。它返回this引用,即相同的映射,因此您可以链接+=调用。请参阅 ScalaDoc 或源代码。

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

如果你做一个scalac -print C.scala 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)

最新更新