闭包函数
Posted handsomepp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了闭包函数相关的知识,希望对你有一定的参考价值。
闭包函数结构
闭包函数作用
- 实现外部也可以访问内部的变量
- 允许将函数与其所操作的某些数据(环境)关联起来
notice
因为函数是复杂数据,其数据在堆区, 当函数调用完后应该被清理数据,但是闭包函数最后用变量赋值给包函数,导致出现内存泄漏
Groovy闭包 Closure ( 闭包参数绑定 | curry 函数 | rcurry 函数 | ncurry 函数 | 代码示例 )
一、闭包参数绑定
闭包 Closure 提供了 curry , ncurry , rcurry 方法 , 这 3 3 3 个方法可以将 闭包 进行 参数绑定 ;
- curry 函数 : 从左到右 绑定 闭包参数 ;
- rcurry 函数 : 从右到左 绑定 闭包参数 ;
- ncurry 函数 : 指定从第 n n n 个参数开始绑定 闭包参数 ;
上述 3 3 3 个方法都会 创建一个新的闭包 , 需要使用 新的变量接收新创建的闭包 , 原来的闭包变量保持不变 ;
1、闭包参数绑定 curry 函数
从左到右绑定参数 ;
闭包参数绑定 curry 函数原型 :
/**
* 从左到右进行参数绑定
* <p>
* 典型用法:
* <pre class="groovyTestCase">
* def multiply = a, b @code -> a * b
* def doubler = multiply.curry(2)
* assert doubler(4) == 8
* </pre>
* 注:对闭包 vararg 类型的功能进行了特殊处理。
* 如果使用vararg参数,则不会使用整个vararg数组,
* 而是使用vararg数组的第一个参数,
* 如下例所示:
* <pre class="groovyTestCase">
* def a = one, two, Object[] others @code -> one + two + others.sum()
* assert a.parameterTypes.name == ['java.lang.Object', 'java.lang.Object', '[Ljava.lang.Object;']
* assert a(1,2,3,4) == 10
* def b = a.curry(1)
* assert b.parameterTypes.name == ['java.lang.Object', '[Ljava.lang.Object;']
* assert b(2,3,4) == 10
* def c = b.curry(2)
* assert c.parameterTypes.name == ['[Ljava.lang.Object;']
* assert c(3,4) == 10
* def d = c.curry(3)
* assert d.parameterTypes.name == ['[Ljava.lang.Object;']
* assert d(4) == 10
* def e = d.curry(4)
* assert e.parameterTypes.name == ['[Ljava.lang.Object;']
* assert e() == 10
* assert e(5) == 15
* </pre>
*
*
* @param arguments 要绑定的闭包参数
* @return 返回已经绑定参数的新的闭包
*/
public Closure<V> curry(final Object... arguments)
return new CurriedClosure<V>(this, arguments);
代码示例 :
// 定义闭包变量 , 声明两个参数 a, b
// 并为闭包指定默认值
def closure5 = a = 0, b = "Groovy" ->
println "$a : $b"
// 闭包有默认值 , 调用时可以不传入参数
closure5()
// 从左到右绑定 闭包参数
def closure6 = closure5.curry(1, "Gradle")
// 闭包有默认值 , 调用时可以不传入参数
closure6()
执行结果 :
0 : Groovy
1 : Gradle
2、闭包参数绑定 rcurry 函数
闭包参数绑定 rcurry 函数是从右到左绑定参数 , 但是 参数的顺序还是从左到右的顺序 , 这点要注意 ;
闭包参数绑定 rcurry 函数原型 :
/**
* 从右到左绑定闭包参数
* 根据普通的 curry()方法,参数在右侧而不是左侧提供。
* 典型用法:
* <pre class="groovyTestCase">
* def divide = a, b @code -> a / b
* def halver = divide.rcurry(2)
* assert halver(8) == 4
* </pre>
*
* curried参数的位置将被延迟计算,
* 例如,如果有两个重载的doCall方法可用,
* 则提供的参数加上curried参数将被连接,结果将用于方法选择。
*
* @param arguments 绑定的参数
* @return 绑定参数后的新闭包
* @see #curry(Object...)
*/
public Closure<V> rcurry(final Object... arguments)
return new CurriedClosure<V>(-arguments.length, this, arguments);
代码示例 :
// 定义闭包变量 , 声明两个参数 a, b
// 并为闭包指定默认值
def closure5 = a = 0, b = "Groovy" ->
println "$a : $b"
// 闭包有默认值 , 调用时可以不传入参数
closure5()
// 从右到左绑定 闭包参数
def closure7 =closure5.rcurry(2, "Java")
// 闭包有默认值 , 调用时可以不传入参数
closure7()
执行结果 :
0 : Groovy
2 : Java
3、闭包参数绑定 ncurry 函数
从第 n n n 个参数开始绑定闭包中的参数 ;
注意调用了 curry / ncurry / rcurry 方法后 , 所有的默认值都被覆盖清除了 , 如果 从第 2 2 2 个参数开始绑定闭包参数 , 则此时第一个参数也没有默认值了 , 调用时 , 必须传入第一个参数只才可以 , 否则运行时会报错 ;
闭包参数绑定 ncurry 函数原型 :
/**
* 从给定的索引处开始绑定闭包参数
*
* @param argument 要绑定参数的闭包
* @return the 绑定参数后新创建的闭包
* @see #ncurry(int, Object...)
*/
public Closure<V> ncurry(int n, final Object argument)
return ncurry(n, new Object[]argument);
代码示例 :
// 定义闭包变量 , 声明两个参数 a, b
// 并为闭包指定默认值
def closure5 = a = 0, b = "Groovy" ->
println "$a : $b"
// 闭包有默认值 , 调用时可以不传入参数
closure5()
// 从第 n 个参数开始绑定闭包参数 ,
// 注意调用了 curry / ncurry / rcurry 方法后 , 之前的默认值就覆盖了
// 此时第一个参数没有值了
// 调用时 , 必须传入第一个参数只才可以
def closure8 =closure5.ncurry(1, "Kotlin")
// 闭包的第一个默认值被取消 , 此时必须传入第一个参数的值才能执行该闭包
// 否则报错
closure8(3)
执行结果 :
0 : Groovy
3 : Kotlin
二、完整代码示例
完整代码示例 :
import org.codehaus.groovy.ant.Groovy
class Test
static void main(args)
// I. 接收默认一个参数的变薄
// 定义闭包变量
def closure =
println "Accept One Arguments : $it"
// 调用闭包
closure.call("Hello");
closure("Hello");
// II. 不接收任何参数的闭包
// 定义闭包变量 , 不允许传入参数
def closure2 = ->
println "Not Accept Arguments"
// 传入参数会报错
//closure2("Hello")
// 调用闭包 , 不能传入参数
closure2.call();
closure2();
// III. 接收一个自定义参数的闭包
// 定义闭包变量 , 声明一个参数 a
def closure3 = a ->
println "$a"
// 调用闭包 , 不能传入参数
closure3.call(1);
closure3(2);
// IV. 接收两个自定义参数的闭包
// 定义闭包变量 , 声明两个参数 a, b
// 在闭包中打印这两个参数
def closure4 = a, b ->
println "$a : $b"
// 调用闭包 , 不能传入参数
closure4.call(1, 2);
closure4(3, 4);
// V. 为闭包参数指定默认值
// 定义闭包变量 , 声明两个参数 a, b
// 并为闭包指定默认值
def closure5 = a = 0, b = "Groovy" ->
println "$a : $b"
// 闭包有默认值 , 调用时可以不传入参数
closure5()
// 从左到右绑定 闭包参数
def closure6 = closure5.curry(1, "Gradle")
// 闭包有默认值 , 调用时可以不传入参数
closure6()
// 从右到左绑定 闭包参数
def closure7 =closure5.rcurry(2, "Java")
// 闭包有默认值 , 调用时可以不传入参数
closure7()
// 从第 n 个参数开始绑定闭包参数 ,
// 注意调用了 curry / ncurry / rcurry 方法后 , 之前的默认值就覆盖了
// 此时第一个参数没有值了
// 调用时 , 必须传入第一个参数只才可以
def closure8 =closure5.ncurry(1, "Kotlin")
// 闭包的第一个默认值被取消 , 此时必须传入第一个参数的值才能执行该闭包
// 否则报错
closure8(3)
执行结果 :
Accept One Arguments : Hello
Accept One Arguments : Hello
Not Accept Arguments
Not Accept Arguments
1
2
1 : 2
3 : 4
0 : Groovy
1 : Gradle
2 : Java
3 : Kotlin
以上是关于闭包函数的主要内容,如果未能解决你的问题,请参考以下文章
Groovy闭包 Closure ( 闭包参数绑定 | curry 函数 | rcurry 函数 | ncurry 函数 | 代码示例 )