省略命名参数倒序的括号

Omiting brackets for named arguments inverts order

http://docs.groovy-lang.org/latest/html/documentation/#_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 中的错误还是某些意外 "groovy goodness"?

这实际上是未记录的 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"}));

它在 Venkat Subramanian 的“编程 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)

"This access() method receives three parameters, but if the first parameter is a Map we can float around the map's key-values in the argument list. (...) Although the kind of flexibility in the Robot example is powerful, it can get confusing, so use it sparingly. (...) We can avoid confusion like this by explicitly naming the first parameter as Map:"

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

顺便说一句,IDE 像 IntelliJ IDEA 有助于理解参数的顺序:

现在,如果我只设置 Map fragile,它会提醒我们的方法调用有问题:

此外,使用 @groovy.transform.TypeChecked@groovy.transform.CompileStatic 注释有助于在编译时捕获此类问题。希望对你有帮助。