我一直用可变地图来计算出现的情况:
var bar = collection.mutable.Map[Int, Int]().withDefaultValue(0)
现在bar(a) += b
工作得很好,无论a
中是否存在密钥bar
已经存在(在这种情况下会被添加)。
我用可变地图的可变地图尝试了同样的事情:
var foo = collection.mutable.Map[Int, collection.mutable.Map[Int, Int]]().
withDefaultValue(collection.mutable.Map().withDefaultValue(0))
如果没有语法糖,foo(a)(b) += x
怎么看?
使用What are all the instances of syntactic sugar in Scala?我会假设它扩展为:
foo.apply(a).put(b, foo.apply(a).apply(b) + x)
但为什么这不会像介绍示例那样相应地更新foo
(例如foo
如果之前不存在,则a
将不具有密钥foo(a)(b) += x
的专用值?
修改:Perseids pointed out,getOrElseUpdate
将更改可变的默认值。这是一个理想的功能吗?
使用DaoWen建议的Int => Int => Int
似乎是克服这两个问题的最佳方法。但是虽然这对于Int => Int => Int => Int => Int
类型的函数很有效,但对于{{1}}类型的函数来说它变得非常麻烦。所以我仍然对任何建议感到高兴!
答案 0 :(得分:3)
这实际上是withDefaultValue
的问题,而不是+=
运算符。如果给定的密钥不存在,则withDefaultValue
的第一个foo
会返回一个新的可变映射。当您执行查找foo(a)(b)
时,如果foo(a)
不存在,则会返回一个新地图,我们将其称为tmp
。 foo(a)(b) += x
然后基本上扩展到:
val tmp = foo(a)
tmp(b) += x
问题是tmp
只更新了+=
,而不是foo
。因此,您的更新发生在tmp
,但tmp
在通话后被丢弃,因为它永远不会存储在任何地方。
如果您希望更新父地图,可能需要使用getOrElseUpdate
而不是依赖withDefaultValue
。
注意: 正如Perseids在下面的评论中指出的那样,withDefaultValue
采用按值参数。这意味着每次从地图中获取未设置的密钥时,它都会返回相同的可变地图实例!这是您应该考虑使用getOrElseUpdate
(使用 by-name 参数),或至少withDefault
,它接受一个函数。 (这都假设您实际上想要地图中每个插槽的不同地图实例...)
答案 1 :(得分:1)
如果没有语法糖,
foo(a)(b) += x
怎么看?
这取决于foo(a)(b)
返回的对象是否具有名为+=
的方法。如果确实如此,则相当于:
foo.apply(a).apply(b).+=(x)
如果没有,则相当于:
foo.apply(a).update(b, foo.apply(a).apply(b).+(x))
除非没有foo.apply(a)
的重复评估(我认为。)