Why Map does not work for GString in Groovy?

前端 未结 2 741
庸人自扰
庸人自扰 2020-12-07 01:53

With the following snippet I cannot retrieve gString from a map:

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

def map = [(gString):         


        
相关标签:
2条回答
  • tl;dr: You seem to have discovered a bug in Groovy's runtime argument overloading evaluation.

    Answer:

    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.)

    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.

    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.

    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]
    

    with this expression:

    DefaultGroovyMethods.getAt(map,gString)
    

    then the argument overloading is resolved correctly, and the correct value is found and returned.

    0 讨论(0)
  • 2020-12-07 02:47

    There's nothing wrong with Groovy. A GString is not a String. It is mutable and as such should never be used as a key in a map (like any other mutable object in Java).

    Learn more about this in the docs: http://docs.groovy-lang.org/latest/html/documentation/index.html#_gstring_and_string_hashcodes

    0 讨论(0)
提交回复
热议问题