【问题标题】:Groovy Map.get(key, default) mutates the mapGroovy Map.get(key, default) 改变地图
【发布时间】:2018-07-26 04:00:04
【问题描述】:

我有以下 Groovy 脚本:

mymap = ['key': 'value']
println mymap

v = mymap.get('notexistkey', 'default')

println v
println mymap

当我运行它时,我得到以下控制台输出:

[key:value]
default
[key:value, notexistkey:default]

我很惊讶在调用mymap.get('notexistkey', 'default') 后,第二个参数是给定键不存在时返回的默认值,键notexistkey 被添加到我调用该方法的映射中。为什么?这是预期的行为吗?如何防止这种突变?

【问题讨论】:

  • 自我注意:RTFM。但是我的大脑太偏向python了..

标签: dictionary groovy mutability


【解决方案1】:

改用 Java 的 Map.getOrDefault(key, value)

mymap = ['key': 'value']
println mymap

v = mymap.getOrDefault('notexistingkey', 'default')

println v
println mymap

输出:

[key:value]
default
[key:value]

Groovy SDK 通过DefaultGroovyMethods.get(map, key, default) 添加Map.get(key, default),如果您看一下Javadoc 所说的内容,您就会明白这种行为是意料之中的:

在给定键的映射中查找项目并返回值 - 除非给定键没有条目,在这种情况下,将默认值添加到映射并返回。

这就是这个方法的实现的样子:

/**
 * Looks up an item in a Map for the given key and returns the value - unless
 * there is no entry for the given key in which case add the default value
 * to the map and return that.
 * <pre class="groovyTestCase">def map=[:]
 * map.get("a", []) &lt;&lt; 5
 * assert map == [a:[5]]</pre>
 *
 * @param map          a Map
 * @param key          the key to lookup the value of
 * @param defaultValue the value to return and add to the map for this key if
 *                     there is no entry for the given key
 * @return the value of the given key or the default value, added to the map if the
 *         key did not exist
 * @since 1.0
 */
public static <K, V> V get(Map<K, V> map, K key, V defaultValue) {
    if (!map.containsKey(key)) {
        map.put(key, defaultValue);
    }
    return map.get(key);
}

这是一个相当古老的概念(从 Groovy 1.0 开始)。但是我建议不要使用它——这个.get(key, default) 操作既不是原子的,也不是同步的。当您在为并发访问而设计的ConcurrentMap 上使用它时,问题就开始了——这种方法违反了它的约定,因为containsKeyput 和最终的get 调用之间没有同步。

【讨论】:

  • 谢谢。有趣的设计。在 OOT 期间,您对这种选择背后的基本原理有任何见解吗?
  • @HuguesFontenelle 我不知道,这是很老的概念(从 Groovy 1.0 开始)。但是我建议不要使用它——这个.get(key, default) 操作既不是原子的,也不是同步的。当您在为并发访问而设计的ConcurrentMap 上使用它时,问题就开始了——这种方法违反了它的约定,因为containsKeyput 和最终的get 调用之间没有同步。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-20
  • 1970-01-01
  • 2012-01-10
  • 2015-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多