Groovy:不是所有等于 * 的字符串都等于 *

2w3kk1z5  于 7个月前  发布在  其他
关注(0)|答案(1)|浏览(87)

在使用Groovy编程时遇到了一个奇怪的问题:
我试图从一个HashMap中获取对象,我用Groovy的“插值”特性(即,包含占位符的双引号中的字符串)- cf。下面的例子中的key 1。后来在处理过程中,我试图使用键从该Map中获取对象,这些键是我通过简单地连接字符串而使用不同的方法创建的- cf。下面的例子中的key 2。令我惊讶的是,我无法从我的Map中获得预期的对象。
然后我把它归结为这个例子:

void testGroovyStrings() {
    String foo = "foo"
    String bar = "bar"
    String delim = '#'
    HashMap map = new HashMap();
    
    def key1 = "${foo}${delim}${bar}"  // creating key variant 1

    map.put(key1, new Integer(5))   // putting some object suing the "String" just created

    def key2 = foo + delim + bar; // creating key variant 2
    
    // my expectation was that this should yield the same value as key1 
    // and that I would get back the object that I had entered above. 
    // After all the keys look identical and are treated as "equal":
    System.out.println "key1: '${key1}' - key2: '${key2}'  equal?:${key1 == key2}"
    
    def obj = map.get(key2)       // but this yields null ?!?

    System.out.println "got object: ${obj}"
    
    // only this gave me a clue, why this failed:
    System.out.println "got object: ${key1} (${key1.getClass()}) - ${key2} (${key2.getClass()})"
}

这将产生输出:

key1: 'foo#bar' - key2: 'foo#bar'  equal?:true
got object: null
got object: foo#bar (class org.codehaus.groovy.runtime.GStringImpl) - foo#bar (class java.lang.String)

很明显,HashMap的get()-方法并没有调用key-objects上的equals()-方法,而是使用了一些其他的方法,这导致了一个奇怪的现象,即当用作(Hash)Map的键时,传递“==”运算符作为相等的键并不是真正相等的。
可以通过将插值后的字符串转换为“java.lang.String”来实现这一点,如下所示:

def key1 = "${foo}${delim}${bar}".toString()

但这看起来又丑又冗长:-(
我的问题是:这是(不)工作的设计或我错过了一些(编译器)设置或有一种方法来解决这个问题?或者我应该向Groovy运行时提交一个bug?其他建议?

7gs2gvoe

7gs2gvoe1#

应该避免使用Groovy模板化字符串作为Map的键
在您的示例中,key1是一个GString(模板化Groovy String)
key2是一个String
如果切换到

def key1 = "${foo}${delim}${bar}".toString()  // creating key variant 1

它应该像你期望的那样工作。
看了你说你知道的编辑:-)
这是通过设计实现的,Groovy String的一个怪癖是它们不能成为好的Map键。没有编译器设置,没有必要提出一个问题,因为已经有很多了。

相关问题