4

grails2.0.3のLinkedHashMapからいくつかの紛らわしい動作に遭遇しています。grailsコンソールで次のスクリプトを実行します。

def m = ["smart-1":[stuff:'asdf']]
println m.getClass()

def p = [id:1]
println m."smart-$p.id"
println m["smart-$p.id"]
println m.get("smart-$p.id")

println m.'smart-1'
println m['smart-1']
println m.get('smart-1')

出力を与えます:

class java.util.LinkedHashMap
[stuff:asdf]
[stuff:asdf]
null
[stuff:asdf]
[stuff:asdf]
[stuff:asdf]

統合テストでは、反対の動作が見られます。HashMapのコンテンツはm.get(GStringImpl)(ではなく m.get(String))を使用してのみ取得できます。

この動作は予想されるか、既知ですか?

4

1 に答える 1

19

まず、ハッシュマップキーでGStringを使用しないでください。これまで。GStringは文字列(そのページの赤いボックス)ではなく、同じハッシュ値を持たないため、ほとんどの場合、アイテムの取得で問題が発生します。代わりに、次のいずれかのオプションを使用してください。

def key = 'key'
['key': value]
[(key): value]
[("some $key".toString()): value]

これにより、文字列を使用するときに常に結果が得られます。(したがって、ルックアップには、常に文字列も使用します。)

なぜあなたが奇妙な振る舞いを見ているのか100%はわかりませんが、確かな推測があります。このget()メソッドはJavaメソッドですが、配列スタイル(およびおそらくプロパティスタイル)のルックアップはgetAt()、Groovy(GDK)メソッドであるを使用して実装されます。私の推測では、GroovyメソッドはGStringを認識しており、つまずかないように変換をサイレントに処理します。

最も簡単な解決策は、常にgetAt()ではなく、を使用することgetです。

def m = ['smart-1':[stuff:'asdf']]
println m.getClass()

def p = [id:1]
println m."smart-$p.id"
println m["smart-$p.id"]
println m.getAt("smart-$p.id")

println m.'smart-1'
println m['smart-1']
println m.getAt('smart-1')

これは問題なく動作します。

より良い解決策は、次のように、値を検索するときに文字列を使用していることを確認することです。

println m.get("smart-$p.id".toString())

これも機能します。メソッドを直接呼び出すと、キーが文字列であることが明確になるため、このメソッドの方が好きです。配列スタイルまたはプロパティスタイルのアクセサーを使用する場合は、標準のGroovy構文であるため、通常のGStringを使用します。


統合テストでは、逆の動作が見られます。HashMapのコンテンツは、(m.get(String)ではなく)m.get(GStringImpl)を使用してのみ取得できます。

これは、ハッシュマップのキーがGStringのままであることが原因である可能性があります。

GStringに変数がない場合、Groovyコンパイラはそれをサイレントに文字列リテラルに変換します(パフォーマンスが向上します)。そのため、上記の例では実際には文字列をキーとして使用していますが、ルックアップではGStringを使用しています。

例えば

"Hello $name" -> GString('Hello $name')
"Hello Bob"   -> 'Hello Bob'

get()最後の考え: Groovyは、はるかにクリーン[]でプロパティの構文を提供するため、 groovyを使用している限り、を使用しないでください。

于 2012-05-10T06:21:06.087 に答える