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