【问题标题】:Why I cannot get exactly the same GString as was put to map in Groovy?为什么我不能得到与在 Groovy 中映射的完全相同的 GString?
【发布时间】:2016-08-25 12:18:01
【问题描述】:

使用以下 sn-p 我无法从地图中检索 gString

def contents = "contents"
def gString = "$contents"

def map = [(gString): true]

assert map.size() == 1 // Passes
assert gString.hashCode() == map.keySet().first().hashCode() // Passes, same hash code
assert gString.is(map.keySet().first()) // Passes, exactly the same object
assert map[gString] // Fails

怎么可能?

这里有趣的是map.get(map.keySet()[0]) 可以正常工作,而map.get[map.keySet()[0]] 不能。

断言消息清楚地表明有问题:

assert map[gString] // Fails
       |  ||
       |  |contents
       |  null
       [contents:true]

这和Why groovy does not see some values in dictionary?不是同一个问题 那里的第一个答案表明:

您将 GString 实例作为键添加到地图中,然后使用 String 实例搜索它们。

在这个问题中,我明确添加了GString 并尝试检索GString

Why are there different behaviors for the ways of addressing GString keys in maps?Groovy different results on using equals() and == on a GStringImpl 也没有给我答案。我不会改变任何东西,也不会将StringGString 混合在一起。 Groovy documentation 也无济于事。

【问题讨论】:

  • 非常好的问题,也许您应该在票证中添加map.get[map.keySet()[0]] 不起作用,但map.get(map.keySet()[0]) 工作正常。
  • @Vampire 谢谢,编辑过的问题——确实很有趣
  • 只需添加 map[gString] = 1; 即可生成这张有趣的地图 [contents:true, contents:1]。几乎就像getAt/putAt 使用 gStrings 的字符串表示...
  • 请在此处查看我的 cmets 关于您的(错误排除的)问题:stackoverflow.com/questions/39141245/…。您似乎发现了一个合法的错误。 Groovy 运行时似乎将map[gString] 动态映射到DefaultGroovyMethods.getAt() 的错误重载。

标签: dictionary groovy gstring


【解决方案1】:

tl;dr:您似乎在 Groovy 的运行时参数重载评估中发现了一个错误。

答案:

map[gString] 在运行时通过 Groovy 的运算符重载机制直接评估为 map.getAt(gString)。到目前为止,一切都很好,但现在一切都开始出错了。 Java LinkedHashMap 类在其类型层次结构中的任何地方都没有 getAt 方法,因此 Groovy 必须使用动态关联的 mixin 方法(实际上该语句有点颠倒。Groovy 之前使用了 mixin 方法使用类层次结构中声明的方法。)

因此,长话短说,Groovy 将map.getAt(gString) 解析为使用类别方法DefaultGroovyMethods.getAt()。轻而易举,对吧?除了此方法有大量不同的参数重载,其中一些可能适用,尤其是当您考虑到 Groovy 的默认参数强制时。

不幸的是,Groovy 没有选择看起来是完美匹配的DefaultGroovyMethods.getAt(Map<K,V>,K),而是选择了DefaultGroovyMethods.getAt(Object,String),它将GString 键参数强制转换为String。由于实际的键实际上是GString,因此该方法最终无法找到值。

对我而言,真正的杀手锏是,如果直接从代码中执行参数重载解析(而不是在运算符解析和类别方法选择之后),那么 Groovy 会做出正确的重载选择!也就是说,如果你替换这个表达式:

map[gString]

用这个表达式:

DefaultGroovyMethods.getAt(map,gString)

然后参数重载被解析正确,找到并返回正确的值。

【讨论】:

    猜你喜欢
    • 2019-09-07
    • 2017-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    • 2011-06-29
    • 1970-01-01
    • 2018-08-01
    相关资源
    最近更新 更多