Пропуск скобок для именованных аргументов инвертирует порядок - PullRequest
0 голосов
/ 16 октября 2018

В http://docs.groovy -lang.org / latest / html / documents / # _ named_arguments нет ничего, что могло бы объяснить это поведение.

def foo(String a,Map b) { println "a: ${a}; b: ${b}" }
foo('a',b : 'c')

В результате возникает ошибка: No signature of method: Script1.foo() is applicable for argument types: (java.util.LinkedHashMap, java.lang.String) values: [[b:c], a]

def foo(String a,Map b) { println "a: ${a}; b: ${b}" }
foo('a',[b : 'c'])

Распечатывает: a: a; b: [b:c]

Смена порядка аргументов в определении также приводит к компиляции:

def foo(Map b,String a) { println "a: ${a}; b: ${b}" }
foo('a',b : 'c')

Распечатывает a: a; b: [b:c]

Это ошибка в Groovy или неожиданная "отличная черта"?

1 Ответ

0 голосов
/ 16 октября 2018

Это фактически недокументированное поведение Groovy.При использовании именованных параметров с дополнительными параметрами Groovy ожидает, что параметр Map, который обозначает именованные параметры, является первым параметром метода, если вы пропустите квадратные скобки в определении карты.Если мы проанализируем байт-код, сгенерированный компилятором, то увидим следующую строку:

foo('a',b : 'c')

выражается следующим кодом Java:

CallSite[] var1 = $getCallSiteArray();
return var1[1].callCurrent(this, ScriptBytecodeAdapter.createMap(new Object[]{"b", "c"}), "a");

Как вы можете видеть порядок параметров, передаваемых вcallCurrent() метод обратный по сравнению с тем, который вы определили при вызове foo() метода.Это немного сбивает с толку, особенно то, что добавление квадратных скобок явно изменяет сгенерированный байт-код:

foo('a', [b: 'c'])

выражается следующим кодом Java:

CallSite[] var1 = $getCallSiteArray();
return var1[1].callCurrent(this, "a", ScriptBytecodeAdapter.createMap(new Object[]{"b", "c"}));

Это кратко объяснено в " Программирование Groovy 2 " книга Венката Субраманиана:

class Robot {
   def type, height, width

   def access(location, weight, fragile) {
       println "Received fragile? $fragile, weight: $weight, loc: $location"
   }
}

robot = new Robot(type: 'arm', width: 10, height: 10)
robot.access(x: 30, y: 20, z: 10, 50, true)
robot.access(50, true, x: 30, y: 20, z: 10)

" Этот access() метод получает три параметра, но если первый параметр - Map, мыможет плавать вокруг значений ключа карты в списке аргументов. (...) Хотя гибкость в примере Robot является мощной, она может привести к путанице, поэтому используйте ее с осторожностью. (...) Мы можем избежатьпутаница, как это, явно назвав первый параметр Map: "

def access(Map location, weight, fragile) { /* .. */ }

Кстати, IDE, как IntelliJ IDEA помогает понять порядок параметров:

enter image description here

Теперь, если я только установлю Map fragile, он предупредит, что с вызовом нашего метода что-то не так:

enter image description here

Также с помощью аннотаций @groovy.transform.TypeChecked и @groovy.transform.CompileStaticловить такие проблемы во время компиляции.Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...