8

次のスニペットでは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 map[gString] // Fails

一体どうしてそれが可能なのでしょうか?

アサーション メッセージは、Groovy に深刻な問題があることを明確に示しています。

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

なぜgroovyが辞書にいくつかの値を表示しないのと同じ質問ではありませんか? 最初の答えは次のとおりです。

GString インスタンスをキーとしてマップに追加し、String インスタンスを使用してそれらを検索しています。

この質問では、 を明確に追加GStringして取得しようとしていますGString

また、マップで GString キーをアドレス指定する方法に異なる動作があるのはなぜですか? また、GStringImpl で equals() および == を使用した場合の Groovy の異なる結果にも、答えはありません。私は何も変異させず、 と混合StringしませんGString

4

2 に答える 2

9

tl;dr: Groovy のランタイム引数のオーバーロード評価でバグを発見したようですね。

答え:

map[gString]map.getAt(gString)Groovy の演算子のオーバーロード メカニズムを介して実行時に直接評価されます。ここまでは順調ですが、ここからすべてがうまくいかなくなります。JavaLinkedHashMapクラスはその型階層のどこにもメソッドを持たないgetAtため、Groovy は代わりに動的に関連付けられた mixin メソッドを使用する必要があります (実際には、そのステートメントは逆です。Groovy は、クラス階層で宣言されたメソッドを使用する前にmixin メソッドを使用します)。

つまり、簡単に言うと、Groovymap.getAt(gString)はカテゴリ メソッドを使用することを決定しますDefaultGroovyMethods.getAt()。簡単ですよね?ただし、このメソッドには多数の異なる引数のオーバーロードがあり、特に Groovy のデフォルトの引数強制を考慮した場合に、そのいくつかが適用される可能性があります。

DefaultGroovyMethods.getAt(Map<K,V>,K)残念ながら、 Groovy は、完全に一致するように見える を選択する代わりに、キー引数DefaultGroovyMethods.getAt(Object,String)を強制的に に変換する を選択します。実際のキーは実際には aであるため、メソッドは最終的に値を見つけることができません。GStringStringGString

私にとって本当のキラーは、引数のオーバーロードの解決が (演算子の解決とカテゴリ メソッドの選択の後ではなく) コードから直接実行される場合、Groovy が正しいオーバーロードの選択を行うことです! つまり、この式を置き換えると、次のようになります。

map[gString]

この表現で:

DefaultGroovyMethods.getAt(map,gString)

次に、引数のオーバーロードが正しく解決され、正しい値が検出されて返されます。

于 2016-08-26T19:44:35.850 に答える
-3

Groovyには何の問題もありません。GString は文字列ではありません。これは可変であるため、(Java の他の可変オブジェクトと同様に) マップ内のキーとして使用しないでください。

ドキュメントでこれについて詳しく学んでください: http://docs.groovy-lang.org/latest/html/documentation/index.html#_gstring_and_string_hashcodes

于 2016-08-25T09:26:19.630 に答える