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