2012-05-10 3 views
4

LinkedHashMap에서 혼란스러운 동작을하고 있습니다. grails 2.0.3입니다. Grails의 콘솔에서 다음 스크립트를 실행 :Groovy/Grails LinkedHashMap 이상하게 동작합니다.

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

이 동작이 예상 또는 알려진 있습니까?

답변

19

먼저 해시 맵 키에 GString을 사용하지 마십시오. 이제까지. GString is not a String (해당 페이지의 빨간색 상자)과 같은 해시 값이 없기 때문에 거의 항상 항목을 검색하는 데 문제가 있습니다. 대신 다음 옵션 중 하나를 사용하십시오.

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

이렇게하면 문자열을 사용할 때 항상 결과를 얻을 수 있습니다. (조회를 위해 항상 문자열을 사용하십시오.)

이상한 행동을하는 이유를 100 % 확신하지는 않지만 확실한 추측을 가지고 있습니다. get() 메서드는 Java 메서드이며 배열 스타일 (및 속성 스타일) 조회는 Groovy (GDK) 메서드 인 getAt()을 사용하여 구현됩니다. 내 생각에 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()) 

. 메서드를 직접 호출 할 때 키가 문자열이라는 점이 분명하기 때문에이 메서드가 더 마음에 듭니다. 배열 스타일 또는 속성 스타일 접근자를 사용할 때 일반 GString을 사용합니다. 그 이유는 표준 Groovy 구문이기 때문입니다. 통합 테스트에서


, 나는 정반대의 행동을보고 있어요 - 난 단지 (반대 m.get (문자열) 등)의 HashMap 사용 m.get (GStringImpl)의 내용을 얻을 수 있습니다.

해시 맵의 키가 GString을 유지하고 있기 때문에 가능성이 높습니다.

GString에 변수가 없으면 Groovy 컴파일러는이를 String 리터럴 (성능 향상)으로 자동 변환합니다. 위의 예제에서 실제로 String을 키로 사용하지만 룩업에서는 GString .

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

마지막 생각 : 당신이 그루비에있는 것처럼 그루비가 훨씬 청소기 []과 재산 구문을 제공하기 때문에 한,, get()를 사용하지 마십시오.

+0

+1 최종 생각 :). 'map [ 'key']'와'map.key'는'map.getAt (key)'의 문법 설탕 일뿐입니다. 그래, 가능하다면 항상 그 두 가지 옵션을 사용하는 것이 좋습니다. – epidemian

+0

종합적인 답변을 주셔서 감사합니다. – Alex

+0

의심 스럽지만 내 앱의지도 키는 GString입니다. '.toString()'호출을 추가하면 맵이 예상대로 작동합니다. 감사 : ¬) – Alex

관련 문제