2016-08-25 1 views
3

С следующего фрагментом я не могу извлекать gString из карты:Почему карта не работает для GString в Groovy?

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 

Как на земле это возможно?

Assertion сообщение ясно показывает, что есть что-то серьезно не так с Groovy:

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

Это не тот же самый вопрос, как Why groovy does not see some values in dictionary? Первый ответ там говорит:

Вы добавляете экземпляры GSTRING, как на вашей карте, а затем искать их с помощью экземпляров String.

В этом вопросе я четко добавить GString и попытаться получить GString.

Также у меня нет Why are there different behaviors for the ways of addressing GString keys in maps? или Groovy different results on using equals() and == on a GStringImpl. Я ничего не мутирую, и я не смешиваю String с GString.

+0

http://stackoverflow.com/questions/31713359/why-are-there-different-behaviors-for-the-ways-of-addressing-gstring-keys-in-map –

+0

http://stackoverflow.com/questions/9682206/groovy-different-results-on-use-equals-and-on-a-gstringimpl –

+1

Тим, эти вопросы не дают мне ответа - они касаются изменчивости или смешивания 'String' с' GString'. В моем коде я не мутирую и не смешиваю ничего. –

ответ

3

Tl; Др: Вы, кажется, обнаружили ошибку в аргументе выполнения Groovy, перегрузки оценки.

Ответ:

map[gString] оценивается как map.getAt(gString) во время выполнения прямолинейно с помощью оператора в Groovy перегрузки механизма. Пока что так хорошо, но теперь все начинает сходить с ума. Класс Java LinkedHashMap не имеет метода getAt в любом месте иерархии своего типа, поэтому Groovy должен вместо этого использовать динамически связанные методы mixin (на самом деле этот оператор является своего рода обратным. Groovy использует методы mixin до с использованием объявленных методов в иерархии классов.)

Итак, чтобы сделать длинный рассказ коротким, Groovy разрешает map.getAt(gString) использовать метод категории DefaultGroovyMethods.getAt(). Легко-peasy, правильно? За исключением того, что этот метод имеет большое количество различных перегрузок аргументов, некоторые из которых могут применяться, особенно когда вы принимаете во внимание аргумент Groovy по умолчанию.

К сожалению, вместо того, чтобы выбрать DefaultGroovyMethods.getAt(Map<K,V>,K), который, казалось бы, идеальный матч, Groovy выбирает DefaultGroovyMethods.getAt(Object,String), которые принуждают к GString ключевой аргумент в String. Поскольку фактический ключ на самом деле является GString, метод в конечном счете не может найти значение.

Для меня настоящим убийцей является то, что если разрешение перегрузки аргументов выполняется непосредственно из кода (вместо того, чтобы после разрешения оператора и выбора метода категории), Groovy делает правильный выбор перегрузки!То есть, если заменить это выражение:

map[gString] 

с этим выражением:

DefaultGroovyMethods.getAt(map,gString) 

то аргумент перегрузки разрешен правильно и правильное значение найдено и возвращено.

+0

@ roger.glover вы бы поняли, почему существует подобная проблема с системными значениями свойств? http://stackoverflow.com/questions/42212368/different-results-when-setting-getting-system-properties-with-gstrings-in-groovy – Dustin

-1

В Groovy нет ничего плохого. A GString - не a Строка. Он изменен и как таковой никогда не должен использоваться в качестве ключа на карте (например, любой другой изменяемый объект в Java).

Подробнее об этом в документации: http://docs.groovy-lang.org/latest/html/documentation/index.html#_gstring_and_string_hashcodes

+1

I ' ve обновленный вопрос с еще одним хеш-кодом assert - это то же самое, и я не мутирую это 'GString' вообще –

+1

, кроме того, использование измененных объектов в качестве ключей карты отлично, пока объект не мутируется после вставки в карту. –

Смежные вопросы