问题描述
使用以下代码段,我无法从地图中检索 gString
:
With the following snippet I cannot retrieve gString
from a map:
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 map[gString] // Fails
如何可能?
断言消息清楚地表明,Groovy有一些严重错误:
Assertion message clearly shows that there's something seriously wrong with Groovy:
assert map[gString] // Fails
| ||
| |contents
| null
[contents:true]
It's not the same question as Why groovy does not see some values in dictionary?First answer there suggests:
在这个问题中,我清楚地添加了 GString
并尝试检索 GString
。
In this question I clearly add GString
and try to retrieve GString
.
既不是也不是在GStringImp上使用equals()和==的不同结果我有一个答案给我。我不会改变任何东西,我不会将 String
与 GString
混合
推荐答案
tl; dr:您似乎在Groovy的运行时参数重载评估中发现了一个错误。
tl;dr: You seem to have discovered a bug in Groovy's runtime argument overloading evaluation.
答案:
map [gString]
code> map.getAt(gString)在运行时直接通过Groovy的操作员重载机制。到目前为止,这么好,但现在是一切都开始失误的地方。 Java LinkedHashMap
类在其类型层次结构中的任何地方都没有 getAt
方法,所以Groovy必须使用动态关联的mixin方法相反(实际上,这种说法是有些颠倒的,Groovy使用在类层次结构中声明的方法之前的之前的混合方法。)
map[gString]
is evaluated as map.getAt(gString)
at runtime straightforwardly via Groovy's operator overloading mechanism. So far, so good, but now is where everything starts to go awry. The Java LinkedHashMap
class does not have a getAt
method anywhere in it's type hierarchy, so Groovy must use dynamically associated mixin methods instead (Actually that statement is sort of reversed. Groovy uses mixin methods before using the declared methods in the class hierarchy.)
所以,做一个很长的故事,Groovy解决 map.getAt(gString)
使用类别方法 DefaultGroovyMethods.getAt()
。容易,对吧?除了这种方法有大量不同的参数重载,其中几个可能适用,特别是当您将Groovy的默认参数强制考虑在内时。
So, to make a long story short, Groovy resolves map.getAt(gString)
to use the category method DefaultGroovyMethods.getAt()
. Easy-peasy, right? Except that this method has a large number of different argument overloads, several of which might apply, especially when you take Groovy's default argument coercion into account.
不幸的是, Groovy选择 DefaultGroovyMethods.getAt(Map< K,V>,K)
,这似乎是一个完美匹配,Groovy选择 DefaultGroovyMethods.getAt(Object,字符串)
,它将 gString
键参数强加到 String
中。由于实际的键实际上是一个 GString
,该方法最终找不到该值。
Unfortunately, instead of choosing DefaultGroovyMethods.getAt(Map<K,V>,K)
, which would seem to be a perfect match, Groovy chooses DefaultGroovyMethods.getAt(Object,String)
, which coerces the GString
key argument into a String
. Since the actual key is in fact a GString
, the method ultimately fails to find the value.
对我来说真正的杀手是,如果参数重载分辨率直接从代码执行(而不是在操作符解析和类别方法选择之后),那么Groovy会使正确的重载选择!也就是说,如果你替换这个表达式:
To me the real killer is that if the argument overload resolution is performed directly from code (instead of after the operator resolution and the category method selection), then Groovy makes the right overload choice! That is to say, if you replace this expression:
map[gString]
使用此表达式:
DefaultGroovyMethods.getAt(map,gString)
然后参数重载已正确解析,而找到并返回正确的值。
then the argument overloading is resolved correctly, and the correct value is found and returned.
这篇关于为什么Map不适用于Groovy中的GString?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!