深入了解groovy:(2)闭包

闭包在groovy语言经常使用,其重要性不言而喻。

1 闭包概念

闭包是一个可执行的代码块,可以通过变量引用,也可以传递给别的函数处理。闭包大大的简化了容器的遍历,提升了代码的可扩展性。

2 定义闭包

用大括号括起来的代码

def clo = {println("hello wold")}

3 闭包调用

call()方法或者直接()

clo.call()
clo()

4 闭包的参数

def clo = { para -> println "$para" } //定义一个有参数的闭包

参数和方法之间用 -> 连接,参数类型可省略,当只有一个参数时,可以用关键字 it 来访问该参数,一个参数时也可以省略,多个参数时用逗号隔开。

def clo = { println it } //只有一个参数可以用it访问
clo.call(1) //输出 1
def clo1 = { para1,para2 -> println para1 + para2 }
clo(1,2) //返回1+2的值
def clo2 = { para1,para2,para3=3 -> para1+para2+para3 }//带默认参数的闭包
clo2.call(1,2) //计算 1+2+3
clo.call(1,2,4) //这样会覆盖参数para3 

5 闭包返回值

闭包一定有返回值,可采用return显性返回,如果没有return,就默认最后一条语句的值为返回值为

def clo = { println "hello wold" } //返回值为null,注意null也是一个值
def clo1 = {para -> para + 1 } //返回值为 para + 1

6 闭包与函数的区别

了解闭包与函数有哪些不同,就可以理解闭包相比于函数的优势。
6.1 闭包可以嵌套,函数不可以

def clo = { para -> { para + it } } //嵌套
clo(2)(3) //调用

6.2 闭包可以访问外部变量,函数不可以

def x = 5
def clo = { it + x }
clo.call(10)

下面就是错误的

def x = 5
def func(){ println "$x" } //编译无法通过,找不到x

注意:方法访问局部变量的方法
将变量的作用域改成全局
采用闭包传递参数

x = 5
def func(){ println "$x" } //编译通过,这是因为不用def定义的变量其实是全局变量

通过闭包传递参数:

def x = 5
def clo = { x } //这样就获取到x的值
def func(clo){ clo.call() + 1 } //将x的值加1
func(clo) 

6.3 调用方式不同
闭包调用:

clo.call()
clo()

函数用函数名称调用

function()
function para //省略括号也是允许的

6.4 返回值不同
闭包一定有返回值,前面已经说到了,函数可以没有返回值,void类型的函数没有返回值。

6.5 参数不同
闭包可以有参数,如果没有定义参数,则有一个默认参数it。函数可以没有参数。

7 闭包科里化

科里化也是闭包的一个重要特点,我们可以开发更多功能。科里化即将多个变量的函数拆解为单变量的函数依次调用。关键字curry。

//科里化示例
def clo = { x,y -> x*y }
def curryclo = clo.curry(2) //对clo进行科里化,等价于 curryclo = { y -> 2*y } 第一个参数被2替代
curryclo.call(3) //计算2*3

科里化的用处:

//实现闭包符合
def clo1 = {x->x*x}
def clo2 = {y->y+y} //定义两个闭包,利用curry实现两个闭包的组合
def clo3 = {f,g,e -> f(g(e))} //定义组合后的闭包,即定义组合规则
def clo4 = clo3.curry(clo1,clo2) //相当于 (y+y)*(y+y)
clo4.call(2)
//去冗余,将复杂参数去除
def clo5 = {p1,p2->println "$p1+$p2"}
Data data = new Data()
def curryclo5 = clo5.curry(data)
curryclo5("hello")
curryclo5("world")
//制造函数工厂
def clopow = {x,y -> y**x} //y的x次方
def clo22 = clopow.curry(2) //生成一个计算平方的函数
def clo33 = clopow.curry(3) //生成一个计算三平方的函数

8 闭包的作用

最常见的用处就是迭代集合
回调:在函数中call闭包
实现高阶函数
特殊的控制逻辑
动态方法定义
资源分配
线程处理

9 闭包的坑

9.1 return:在闭包循环中使用return并不会退出循环

def list = [1,2,3,4]
list.each{
	if(it == 3)
		return it //遇到此处并没有退出,执行结果为124
	print(it)
}

跳出循环则用return true
each中return true相当于continue
find中return true相当于break
9.2 隐藏参数it
当且仅当闭包中有且仅有一个参数,且不显示声明,it具有唯一参数引用的作用,其他情况下,如果在闭包参数声明中没有it,那么闭包的逻辑代码块中的it降级为普通的变量

def clo = {p1 -> 
	def it = 1 
	return it + p1  //it为普通变量
}
println clo.call(3)  //结果为1+3

当外部也定义了it,则优先使用外部的变量

it = 1
def clo = {p1 -> println "$it"}
clo.call(3)  //结果为1

闭包嵌套时内部闭包的参数it与外部闭包it不会相互影响

def clo = {
	println it
	def clo2 = {
		println it
	}
	clo2.call()  //输出null,不会获得外部it的值
}
clo.call(3) //输出:3 null
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页