Groovy 的多重赋值和方法的多返回值
追溯到刚开始学习 Groovy 还是在 2008 年,距今 2018 年有九年半余,曾记下几篇 Groovy
的日志。那时学习 Groovy 并无明确的目的,只因它是脚本语言, 可用来快速验证 Java API。曾经 BeanShell 芸花一现,
JRuby 和 Jython 总是别人家的语言照搬而来的。而 Scala,Nashorn(jjs), JShell 更是后来的事,唯有 Groovy 写起来很亲切,完全不懂 Groovy 都没关系,直接上 Java。
现如今之所以重新勾搭上了 Groovy 是因为它仍然坚挺着,在 SoupUI(ReadyAPI) 和 Jenkins 中获得了重视,倒不是因为 Gradle。先前 Groovy 在 Spring 框架中的地位估计要被如今的 Kotlin 取而代之。
好了,回顾完后进入正题,关于 Groovy 如何进行多重赋值,以及延伸到方法返回多个值的情形。这里所说的多重赋值不是指用连等号来同时赋为一个值,
def a = b = c = 100 //不是说的这个
而是指同时对多个变量一步到位的赋成不同的值,要实现这个必须用到 List 类型。看下面一个基本例子(GroovyConsole)
基本语法就是
右边中括号声明的是一个
凡事都得举一反三
一般情况下我比较爱在 Groovy Shell 下进行简单的测试,但是发现 Groovy Shell 下用
加了
左边多余的变量会被声明为
列表从左自右只提取需要的元素分别赋值左边的变量
上面直接用的 list[0], list[1], 和 list[2..01] 来得到 a, b, rest 的值。
而 Scala 从 Tuple 或各类集合中提取元素所展现的是它强大的模式匹配功能,Groovy 在这点上是不太具备的。
那是否能用下面的形式一次性声明 id 和 name 两个变量,并从 user 实例中获得相应的值呢?
Groovy 报出异常
链接:
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
现如今之所以重新勾搭上了 Groovy 是因为它仍然坚挺着,在 SoupUI(ReadyAPI) 和 Jenkins 中获得了重视,倒不是因为 Gradle。先前 Groovy 在 Spring 框架中的地位估计要被如今的 Kotlin 取而代之。
好了,回顾完后进入正题,关于 Groovy 如何进行多重赋值,以及延伸到方法返回多个值的情形。这里所说的多重赋值不是指用连等号来同时赋为一个值,
def a = b = c = 100 //不是说的这个
而是指同时对多个变量一步到位的赋成不同的值,要实现这个必须用到 List 类型。看下面一个基本例子(GroovyConsole)
基本语法就是1def(var1, var2, var3) = [value1, value2, value3]右边中括号声明的是一个
ArrayList, 右边对等位置找到相应的值逐个赋给左边的变量, 前面的例子实际可以理解为下面的过程1list = [1, 'Yanbin]
2id = list.getAt(0)
3name = list.getAt(1)凡事都得举一反三
- 前面赋值是左右元素数目相等,如果是左短右长,或左长右短会是怎样
- 如果只需提取右端列表的某几个元素一条语句该如何做
- 函数如何返回多个值,以及如何一条语句接受函数返回的多个值
- 是否能一条语句获得自定义对象(非 List) 的多个属性值
- 正则表达式多组捕获的字符串是否能一次性的赋给多个变量
一般情况下我比较爱在 Groovy Shell 下进行简单的测试,但是发现 Groovy Shell 下用
def (a, b) = [1, 2] 的形式有个 Bug,去掉 def 关键字就可以了, 看下面的截图
加了 def 关键字后 id 和 name 两个变量反而不可见了,所以接下来的测试中我仍然用 Groovy Shell, 但是会把 def 关键字隐去。左边变量数目多于右边列表元素
1groovy:000> (id, name, address) = [1, 'Yanbin']
2===> [1, Yanbin]
3groovy:000> println "$id, $name, $address"
41, Yanbin, null左边多余的变量会被声明为
null 值左边变量数目少于右边列表元素
1groovy:000> (id, name) = [1, 'Yanbin', 'Earth']
2===> [1, Yanbin, Earth]
3groovy:000> println "$id, $name"
41, Yanbin列表从左自右只提取需要的元素分别赋值左边的变量
关于任意位置提取右边 List 的元素
Groovy 无法简单像 Scala 那样提取任意位置的元素,而必须显式的用[index] 或 getAt(index) 方法。例如1groovy:000> list = [1, 2, 3, 4, 5]
2===> [1, 2, 3, 4, 5]
3groovy:000> def (a, b, rest) = [0, 1, 2..-1].collect { list[it] }
4===> [1, 2, [3, 4, 5]]上面直接用的 list[0], list[1], 和 list[2..01] 来得到 a, b, rest 的值。
而 Scala 从 Tuple 或各类集合中提取元素所展现的是它强大的模式匹配功能,Groovy 在这点上是不太具备的。
Groovy 方法同时返回多个值
有了以上的知识后,要实现 Groovy 方法返回多值就好办了,只要让方法返回一个 List 就行,接收端用 (a, b) = foo() 来进行多重赋值1groovy:000> def getUserInfo() { [1, 'Yanbin'] }
2===> true
3groovy:000> def (id, name) = getUserInfo()
4===> [1, Yanbin]从自定定义对象一次性提取多个属性值
比如,对于一个自定义对象 User,获得实例 user 后,需要分别用user.id 和 user.name 来得到 id 和 name1@groovy.transform.Canonical
2class User {
3 Integer id;
4 String name;
5}
6
7def user = new User(1, 'Yanbin')
8println "${user.id}, ${user.name}" //输出 1, Yanbin那是否能用下面的形式一次性声明 id 和 name 两个变量,并从 user 实例中获得相应的值呢?
1def (id, name) = new user(1, 'Yanbin') //有异常,见下Groovy 报出异常
Exception thrown groovy.lang.MissingMethodException: No signature of method: User.getAt() is applicable for argument types: (java.lang.Integer) values: [0]这个线索给予我们的是
Possible solutions: getAt(java.lang.String), getId(), setId(java.lang.Integer), getName(), putAt(java.lang.String, java.lang.Object), wait()
User 类需要实现 getAt(Integer) 方法,因此对代码的改造如下 1@groovy.transform.Canonical
2class User {
3 Integer id;
4 String name;
5
6 def getAt(Integer index) {
7 switch(index) {
8 case 0: id; break;
9 case 1: name; break;
10 default: throw new IndexOutOfBoundsException(String.valueOf(index))
11 }
12 }
13}
14
15def (id, name) = new User(1, 'Yanbin')
16println "$id, $name" //输出为 1, Yanbindef (id, name) = new User(1, 'Yanbin') 相当于执行了1def user = new User(1, 'Yanbin')
2def id = user.getAt(0)
3def name = user.getAt(1)正则表达式中同时捕获多组值赋给多个变量
代码演示1groovy:000> def (exp, amount, currency) = ('12 Euro' =~ /(\d+) (\w+)/)[0]
2===> [12 Euro, 12, Euro]exp, amount 和 currency 的值分别为 12 Euro, 12 和 Euro。同样的,正则表达式分组中第一个元素是被匹配的字符串本身。链接:
- Groovy Goodness: Multiple Assignments
- Getting tail of a list in Multiple Assignment in Groovy
- Groovy中的隐式构造函数
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。