foo(a)(b)+=x在Scala中是如何工作的?

foo(a)(b)+=x在Scala中是如何工作的?,scala,scala-collections,Scala,Scala Collections,我一直在用一个可变图计算发生率: var bar = collection.mutable.Map[Int, Int]().withDefaultValue(0) 现在bara+=b工作得很好,不管键a是否已经存在于bar中,在这种情况下,它将被添加 我在可变地图的可变地图上也做了同样的尝试: var foo = collection.mutable.Map[Int, collection.mutable.Map[Int, Int]](). withDefaultValue

我一直在用一个可变图计算发生率:

var bar = collection.mutable.Map[Int, Int]().withDefaultValue(0)
现在bara+=b工作得很好,不管键a是否已经存在于bar中,在这种情况下,它将被添加

我在可变地图的可变地图上也做了同样的尝试:

var foo = collection.mutable.Map[Int, collection.mutable.Map[Int, Int]]().
          withDefaultValue(collection.mutable.Map().withDefaultValue(0))
如果没有语法糖,fooab+=x看起来如何

使用,我假设它扩展到:

foo.apply(a).put(b, foo.apply(a).apply(b) + x)
但是为什么不像介绍性示例中那样相应地更新foo本身,即如果键a以前不存在,foo就不会有专用值

Edit:As,fooab+=x将更改可变的默认值。这是您想要的功能吗?
按照的建议使用GetOrelsUpdate似乎是克服这两个问题的最佳方法。但是,虽然这对于Int=>Int=>Int类型的函数很有效,但是对于Int=>Int=>Int=>Int=>Int=>Int类型的函数来说,它变得非常麻烦。所以我还是很乐意接受任何建议

这实际上是withDefaultValue的问题,而不是+=运算符的问题。如果给定的键不存在,那么foo的第一个withDefaultValue将返回一个新的可变映射。当您查找fooab时,如果fooa不存在,那么它将返回一个新的映射,我们称之为tmp。fooab+=x则基本上扩展为:

val tmp = foo(a)
tmp(b) += x
问题是只有tmp被+=,而不是foo更新。因此,您的更新发生在tmp上,但tmp在调用后会被丢弃,因为它从未存储在任何地方

如果希望父映射得到更新,可能需要研究使用GetOrelsUpdate而不是依赖withDefaultValue


注意:正如Perseids在下面的注释中指出的那样,withDefaultValue采用一个by-value参数。这意味着,每次从地图中获取未设置的键时,它都将返回相同的可变地图实例!这是您应该考虑使用GetOrelsUpdate的另一个原因,它使用一个按名称参数,或者至少使用默认值,它接受一个函数。这都是假设您实际上希望地图中的每个插槽都有不同的地图实例…

这实际上是withDefaultValue的问题,而不是+=运算符的问题。如果给定的键不存在,那么foo的第一个withDefaultValue将返回一个新的可变映射。当您查找fooab时,如果fooa不存在,那么它将返回一个新的映射,我们称之为tmp。fooab+=x则基本上扩展为:

val tmp = foo(a)
tmp(b) += x
问题是只有tmp被+=,而不是foo更新。因此,您的更新发生在tmp上,但tmp在调用后会被丢弃,因为它从未存储在任何地方

如果希望父映射得到更新,可能需要研究使用GetOrelsUpdate而不是依赖withDefaultValue

注意:正如Perseids在下面的注释中指出的那样,withDefaultValue采用一个by-value参数。这意味着,每次从地图中获取未设置的键时,它都将返回相同的可变地图实例!这是您应该考虑使用GetOrelsUpdate的另一个原因,它使用一个按名称参数,或者至少使用默认值,它接受一个函数。这都是假设您实际上希望地图中的每个插槽都有不同的地图实例

如果没有语法糖,fooab+=x看起来如何

这取决于fooab返回的对象是否具有名为+=的方法。如果是,那么它相当于:

foo.apply(a).apply(b).+=(x)
foo.apply(a).update(b, foo.apply(a).apply(b).+(x))
如果没有,则相当于:

foo.apply(a).apply(b).+=(x)
foo.apply(a).update(b, foo.apply(a).apply(b).+(x))
我想除了没有foo.applya的重复评估

如果没有语法糖,fooab+=x看起来如何

这取决于fooab返回的对象是否具有名为+=的方法。如果是,那么它相当于:

foo.apply(a).apply(b).+=(x)
foo.apply(a).update(b, foo.apply(a).apply(b).+(x))
如果没有,则相当于:

foo.apply(a).apply(b).+=(x)
foo.apply(a).update(b, foo.apply(a).apply(b).+(x))

除了没有foo.applya的重复计算之外,我认为。

fooa在第一个示例中,fooab在第二个示例中都是Int类型。并且没有+=方法。完全正确,我处于scala daze效应之下!fooab+=x将更改可变的默认值。这是您想要的功能吗?我认为这是设计时考虑到了不变的对象。可以返回与默认值相同的不可变对象,例如Int或不可变映射。对于可变值来说,它不太好用……真的有必要在地图中使用这么多级别的嵌套吗?你能用元组作为键吗?换句话说,第一个例子中的Int,Int,Int,Int=>Int.fooa和第二个例子中的fooab都是Int类型的,而不是Int=>Int=>Int=>Int=>Int,在这个例子中没有+=方法。完全正确,我处于scala-daze效应之下!fooab+=x将更改可变的默认值。这是您想要的功能吗?我认为这是设计时考虑到了不变的对象。可以返回与默认值相同的不可变对象,例如Int或不可变映射。对于可变值来说,它不太好用……真的有必要在地图中使用这么多级别的嵌套吗?你能用元组作为键吗?伊诺
换句话说,不是Int=>Int=>Int=>Int=>Int,而是Int,Int,Int=>Int。这个时间映射是如何生成的?外部withDefaultValue仅获取对可变.Map的具体实例的引用,而不是对工厂的引用。我只是对REPL进行了一些处理,您的解释与我的结果不匹配。我创建了一个数组vala=Array[Int]10,并将其放入withDefaultValue val bar=collection.mutable.Map[Int,Array[Int]].withDefaultValuea。现在bar0 eq a的计算结果为true,即每次找不到密钥时,bar都会返回对a的相同原始引用,而不是a的副本。@Perseids-你是对的。我认为withDefaultValue有一个by-name参数。它不会每次都返回新地图。我认为这是一个完全不同的问题。。。我会更新我的答案。这个时间映射是如何生成的?外部withDefaultValue仅获取对可变.Map的具体实例的引用,而不是对工厂的引用。我只是对REPL进行了一些处理,您的解释与我的结果不匹配。我创建了一个数组vala=Array[Int]10,并将其放入withDefaultValue val bar=collection.mutable.Map[Int,Array[Int]].withDefaultValuea。现在bar0 eq a的计算结果为true,即每次找不到密钥时,bar都会返回对a的相同原始引用,而不是a的副本。@Perseids-你是对的。我认为withDefaultValue有一个by-name参数。它不会每次都返回新地图。我认为这是一个完全不同的问题。。。不过我会更新我的答案。