groovy闭包 list传参
问题现象
如下代码,定义一个闭包接受两个参数,传递参数时可以传递 size = 2 的 List 作为参数, 使用 length = 2 的数组不可以,使用 size = 2 的 Set 也不可以。
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Test void test2() {
def closure = { a, b -> a == '1' ? b.toUpperCase() : b.toLowerCase() }
List param1 = ["1", 'AbCd'] assert 'ABCD' == closure(param1)
String[] param2 = ["1", 'AbCd'] assert 'ABCD' == closure(param2) }
|
翻看文档未找到相关介绍,那为什么可以使用 List 呢?
当然 Groovy 支持 使用*List 的方式,将 List 展平作为参数,这里我并没有使用星号
试了一下单个参数的闭包调用情况
test3 闭包接受一个String类型的参数,传递一个List,会将List数据取出来作为参数传入。 test4闭包未指定参数类型,会将List本身作为参数传入,不会取出数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Test void test3() { def closure = { String a -> a == '1' ? a + 'A' : a + 'B' }
List param1 = ["1"] assert '1A' == closure(param1) }
@Test void test4() { def closure = { a -> a == '1' ? a + 'A' : a + 'B' }
List param1 = ["1"] assert ['1', 'B'] == closure(param1) }
|
源码解析
查看其源码,下面是核心方法
org.codehaus.groovy.runtime.metaclass.ClosureMetaClass#invokeMethod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| Object invokeMethod(Class sender, Object object, String methodName, Object[] originalArguments, boolean isCallToSuper, boolean fromInsideClass) {
final Object[] arguments = makeArguments(originalArguments, methodName); final Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
MetaMethod method = null; final Closure closure = (Closure) object;
if (CLOSURE_DO_CALL_METHOD.equals(methodName) || CLOSURE_CALL_METHOD.equals(methodName)) { method = pickClosureMethod(argClasses); if (method == null && arguments.length == 1 && arguments[0] instanceof List) { Object[] newArguments = ((List) arguments[0]).toArray(); Class[] newArgClasses = MetaClassHelper.convertToTypeArray(newArguments); method = createTransformMetaMethod(pickClosureMethod(newArgClasses)); }
protected MetaMethod createTransformMetaMethod(MetaMethod method) { if (method == null) { return null; }
return new TransformMetaMethod(method) { public Object invoke(Object object, Object[] arguments) { Object firstArgument = arguments[0]; List list = (List) firstArgument; arguments = list.toArray(); return super.invoke(object, arguments); } }; }
|
这应该是闭包的特殊逻辑,其他正常方法是没有这种逻辑的,如果想要将List展平作为参数,仍需使用星号的形式。
以后如果不知道闭包具体参数数量可以直接传递List即可。在dsl中使用会很方便。