闭包
闭包,英文叫Closure,是Groovy中非常重要的一个数据类型或者说一种概念了。闭包的历史来源,种种好处我就不说了。我们直接看怎么使用它!
闭包,是一种数据类型,它代表了一段可执行的代码。其外形如下:
def aClosure = {//闭包是一段代码,所以需要用花括号括起来..
String param1, int param2 -> //这个箭头很关键。箭头前面是参数定义,箭头后面是代码
println"this is code" //这是代码,最后一句是返回值,
//也可以使用return,和Groovy中普通函数一样
}
简而言之,Closure的定义格式是:
def xxx = {paramters -> code} //或者
def xxx = {无参数,纯code} 这种case不需要->符号
说实话,从C/C++语言的角度看,闭包和函数指针很像。闭包定义好后,要调用它的方法就是:
闭包对象.call(参数) 或者更像函数指针调用的方法:
闭包对象(参数)
比如
aClosure.call("this is string",100) 或者
aClosure("this is string", 100)
上面就是一个闭包的定义和使用。在闭包中,还需要注意一点:
如果闭包没定义参数的话,则隐含有一个参数,这个参数名字叫it,和this的作用类似。it代表闭包的参数。
比如:
def greeting = { "Hello, $it!" }
assert greeting('Patrick') == 'Hello, Patrick!'
等同于
def greeting = { it -> "Hello, $it!" }
assert greeting('Patrick') == 'Hello, Patrick!'
但是,如果在闭包定义时,采用下面这种写法,则表示闭包没有参数!
def noParamClosure = { -> true }
这个时候,我们就不能给noParamClosure传参数了!
noParamClosure ("test") <==报错喔!
Closure使用中的注意点
- 省略圆括号
闭包在Groovy中大量使用,比如很多类都定义了一些函数,这些函数最后一个参数都是一个闭包。比如:
public static <T> List<T> each(List<T> self, Closure closure)
上面这个函数表示针对List的每一个元素都会调用closure做一些处理。这里的closure,就有点回调函数的感觉。但是,在使用这个each函数的时候,我们传递一个怎样的Closure进去呢?比如:
def iamList = [1,2,3,4,5] //定义一个List
iamList.each{ //调用它的each,这段代码的格式看不懂了吧?each是个函数,圆括号去哪了?
println it
}
上面代码有两个知识点:
each函数调用的圆括号不见了!原来,Groovy中,当函数的最后一个参数是闭包的话,可以省略圆括号。比如
def testClosure(int a1,String b1, Closure closure){
//do something
closure() //调用闭包
}
那么调用的时候,就可以免括号!
testClosure (4, "test", {
println "i am in closure"
} ) //红色的括号可以不写..
注意,这个特点非常关键,因为以后在Gradle中经常会出现图7这样的代码:
image008.png
经常碰见图7这样的没有圆括号的代码。省略圆括号虽然使得代码简洁,看起来更像脚本语言,但是它这经常会让我confuse(不知道其他人是否有同感),以doLast为例,完整的代码应该按下面这种写法:
doLast({
println 'Hello world!'
})
有了圆括号,你会知道 doLast只是把一个Closure对象传了进去。很明显,它不代表这段脚本解析到doLast的时候就会调用println 'Hello world!' 。
但是把圆括号去掉后,就感觉好像println 'Hello world!'立即就会被调用一样!
- 如何确定Closure的参数
另外一个比较让人头疼的地方是,Closure的参数该怎么搞?还是刚才的each函数:
public static <T> List<T> each(List<T> self, Closure closure)
如何使用它呢?比如:
def iamList = [1,2,3,4,5] //定义一个List变量
iamList.each{ //调用它的each函数,只要传入一个Closure就可以了。
println it
}
看起来很轻松,其实:
对于each所需要的Closure,它的参数是什么?有多少个参数?返回值是什么?
我们能写成下面这样吗?
iamList.each{String name,int x ->
return x
} //运行的时候肯定报错!
所以,Closure虽然很方便,但是它一定会和使用它的上下文有极强的关联。要不,作为类似回调这样的东西,我如何知道调用者传递什么参数给Closure呢?
作者:EvilsoulM
链接:https://www.jianshu.com/p/94aabdfcdfc5
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。