Groovy的named parameter 一般有两个用途:
1. 用在groovybean的构造函数中,提供一种便利的方式来创建新对象。
2. 用在方法中(static or not-static),如果传入的参数是named parameter的话,那么该方法会自动收集这些named parameter,然后当成该方法的第一个参数。
我们先来看看第一种用途,假设我们有下面的groovybean:
class Person {
String name
int age
}
那么groovy会自动的为这个groovybean生成一个带map为参数的构造函数,类似于下面:
class Person {
String name
int age
Person(Map map) { map.each {k,v->
this."${k}"=v
}
}
}
那么我们在创建Person对象的时候,可以通过如下方式来进行:
class TestMain {
static main(args) {
def p =new Person([name:'yezi',age:25])
println p.name
println p.age
}
}
实际上下面这两句是等价的:
def p =new Person([name:'yezi',age:25])
def p =new Person(name:'yezi',age:25)
方括号是可选的。
如果你使用过SPRING的dataBinder来讲HttpServletRequest的参数直接绑定成对象的话,那么就会发现我们也可以通过这个特性来完成spring dataBinder的这个feature。
def httpReq=...
httpReq.setAttribute("name","yezi")
httpReq.setAttribute("age",25)
def p = new Person(httpReq.getParams)
接下来让我们看看第二种用法,我们定义了printlnSth方法:
class Person {
String name
int age
void printlnSth(def params, def otherParams) {
println params.name
println params.age
println otherParams
}
}
然后我们按照下面的方式来进行调用:
class TestMain {
static main(args) {
def p =new Person([name:'yezi',age:25])
p.printlnSth name:"tianzi", "i am other params", age:25
p.printlnSth "i am other params", age:25,name:"tianzi"
}
}
//输出:
tianzi
25
i am other params tianzi
25
i am other params
从上可以看到,如果一个方法传入的参数包含named parameter的话,那么groovy就会自动收集传入的所有named parameter, 然后当作该方法的第一个参数传进去,而不理会named paramter的位置。 但是我们同时也注意到,在定义printlnSth方法的时候,我们都是没有指定参数的类型的(都通过def指定),如果我们直接显式指定printlnSth的第一个参数的类型呢? 比如说指定为map, 如:
class Person {
String name
int age
void printlnSth(Map params, def otherParams) {
println params.name
println params.age
println otherParams
}
}
然后运行TestMain, 发现结果是一样的。
那如果显示指定printlnSth的第一个参数类型为Map之外的类型呢?让我们修改为List后来看看。
class Person {
String name
int age
void printlnSth(List params, def otherParams) {
println params.name
println params.age
println otherParams
}
}
然后再次运行TestMain, 这个时候groovy提示错误了,
Caught: groovy.lang.MissingMethodException: No signature of method: com.yezi.test.Person.printlnSth() is applicable for argument types: (java.util.LinkedHashMap, java.lang.String) values: [[name:tianzi, age:25], i am other params]
从这个错误信息我们可以推断中,如果一个方法,它的传入参数含有named parameter的话,那么groovy就会自动去寻找第一个参数为map的方法来执行(可能方法有重载)。
那么第二种用法一般做什么用呢, 一般是应用于DSL的编写中,假设我们要实现一个方法, 用来表示从哪里开车多少公里到哪里, 那么一般我们会这么定义方法:
class TestMain {
static main(args) {
drive(10,"1130 kifer rd","sfo")
}
static void drive(miles,origin,destination) {
println "drive ${miles} miles from ${origin} to ${destination}"
}
}
但是这样对于不是程序员的业务人员来说是不直观的。但是如果我们定义成下面这样的话:
class TestMain {
static main(args) {
drive(10,from:"1130 kifer rd",to:"sfo")
}
static void drive(addrInfo,miles) {
println "drive ${miles} miles from ${addrInfo.from} to ${addrInfo.to}"
}
}
这样的话,对于业务人员来讲,他也可以写,同时方法调用会显得更加清晰。