Это фактически недокументированное поведение 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 помогает понять порядок параметров:
Теперь, если я только установлю Map fragile
, он предупредит, что с вызовом нашего метода что-то не так:
Также с помощью аннотаций @groovy.transform.TypeChecked
и @groovy.transform.CompileStatic
ловить такие проблемы во время компиляции.Надеюсь, это поможет.