我是靠谱客的博主 碧蓝菠萝,这篇文章主要介绍(2.2.9.3)groovy的闭包,现在分享给大家,希望可以做个参考。

闭包的样子

闭包,英文叫 Closure,是 Groovy 中非常重要的一个数据类型或者说一种概念了。闭包的历史来源,种种好处我就不说了。我们直接看怎么使用它!

闭包,是一种数据类型,它代表了一段可执行的代码。其外形如下:

复制代码
1
2
3
4
5
6
def aClosure = {//闭包是一段代码,所以需要用花括号括起来.. String param1, int param2 -> //这个箭头很关键。箭头前面是参数定义,箭头后面是代码 println "this is code" //这是代码,最后一句是返回值, //也可以使用 return,和 Groovy 中普通函数一样 }

简而言之,Closure 的定义格式是:

复制代码
1
2
3
4
5
def xxx = {paramters -> code} //或者 def xxx = {无参数,纯 code} 这种 case 不需要->符号

说实话,从 C/C++ 语言的角度看,闭包和函数指针很像。闭包定义好后,要调用它的方法就是:

闭包对象.call(参数) 或者更像函数指针调用的方法:

闭包对象(参数)
比如:

复制代码
1
2
3
aClosure.call("this is string", 100) 或者 aClosure("this is string", 100)

上面就是一个闭包的定义和使用。在闭包中,还需要注意一点:

如果闭包没定义参数的话,则隐含有一个参数,这个参数名字叫 it,和 this 的作用类似。it 代表闭包的参数。

比如:

复制代码
1
2
def greeting = { "Hello, $it!" } assert greeting('Patrick') == 'Hello, Patrick!'

等同于:

复制代码
1
2
def greeting = { it -> "Hello, $it!" } assert greeting('Patrick') == 'Hello, Patrick!'

但是,如果在闭包定义时,采用下面这种写法,则表示闭包没有参数!

复制代码
1
def noParamClosure = { -> true }

这个时候,我们就不能给 noParamClosure 传参数了!

复制代码
1
2
3
noParamClosure ("test") <==报错喔!

Closure 使用中的注意点

1.省略圆括号

闭包在 Groovy 中大量使用,比如很多类都定义了一些函数,这些函数最后一个参数都是一个闭包。比如:

复制代码
1
public static <T> List<T> each(List<T> self, Closure closure)

上面这个函数表示针对 List 的每一个元素都会调用 closure 做一些处理。这里的 closure,就有点回调函数的感觉。但是,在使用这个 each 函数的时候,我们传递一个怎样的 Closure 进去呢?比如:

复制代码
1
2
3
4
5
6
def iamList = [1,2,3,4,5] //定义一个 List iamList.each{ //调用它的 each,这段代码的格式看不懂了吧?each 是个函数,圆括号去哪了? println it }

上面代码有两个知识点:

  • each 函数调用的圆括号不见了!原来,Groovy 中,当函数的最后一个参数是闭包的话,可以省略圆括号。比如
复制代码
1
2
3
4
5
def testClosure(int a1,String b1, Closure closure){ //do something closure() //调用闭包 }

那么调用的时候,就可以免括号!

复制代码
1
2
3
4
testClosure (4, "test", { println "i am in closure" } ) //红色的括号可以不写..

注意,这个特点非常关键,因为以后在 Gradle 中经常会出现图 7 这样的代码:

经常碰见图 7 这样的没有圆括号的代码。省略圆括号虽然使得代码简洁,看起来更像脚本语言,但是它这经常会让我 confuse(不知道其他人是否有同感),以 doLast 为例,完整的代码应该按下面这种写法:

复制代码
1
2
3
doLast({ println 'Hello world!' })

有了圆括号,你会知道 doLast 只是把一个 Closure 对象传了进去。很明显,它不代表这段脚本解析到 doLast 的时候就会调用 println 'Hello world!' 。

但是把圆括号去掉后,就感觉好像 println 'Hello world!'立即就会被调用一样!

2.如何确定 Closure 的参数

另外一个比较让人头疼的地方是,Closure 的参数该怎么搞?还是刚才的 each 函数:

复制代码
1
public static <T> List<T> each(List<T> self, Closure closure)

如何使用它呢?比如:

复制代码
1
2
3
4
5
6
def iamList = [1,2,3,4,5] //定义一个 List 变量 iamList.each{ //调用它的 each 函数,只要传入一个 Closure 就可以了。 println it }

看起来很轻松,其实:

  • 对于 each 所需要的 Closure,它的参数是什么?有多少个参数?返回值是什么?

我们能写成下面这样吗?

复制代码
1
2
3
4
5
iamList.each{String name,int x -> return x } //运行的时候肯定报错!

所以,Closure 虽然很方便,但是它一定会和使用它的上下文有极强的关联。要不,作为类似回调这样的东西,我如何知道调用者传递什么参数给 Closure 呢?

此问题如何破解?只能通过查询 API 文档才能了解上下文语义。比如下图 8:

图 8 中:

  • each 函数说明中,将给指定的 closure 传递 Set 中的每一个 item。所以,closure 的参数只有一个。

  • findAll 中,绝对抓瞎了。一个是没说明往 Closure 里传什么。另外没说明 Closure 的返回值是什么.....。

对 Map 的 findAll 而言,Closure 可以有两个参数。findAll 会将 Key 和 Value 分别传进去。并且,Closure 返回 true,表示该元素是自己想要的。返回 false 表示该元素不是自己要找的。示意代码如图 9 所示:

Closure 的使用有点坑,很大程度上依赖于你对 API 的熟悉程度,所以最初阶段,SDK 查询是少不了的。

最后

以上就是碧蓝菠萝最近收集整理的关于(2.2.9.3)groovy的闭包的全部内容,更多相关(2.2.9.3)groovy内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部