Groovy语法学习(四) 闭包总结

版权声明:版权声明:尊重博主原创文章,转载请注明出处 https://blog.csdn.net/a568478312/article/details/79896751

groovy中的闭包,也就是Closure。接触过lambda或者kotlin的同学肯定知道,在java中如果有类似于setxxxListener之类的方法,直接传入一个接口(如果接口只有一个方法,就叫做函数式接口)。然后接口里方法外包装的一层完全没有作用,然后lambda表达式出现解决了这个问题,在java8中就可以使用。Closure就类似于这种形式,不过闭包中有更多的实现,下面来总结一下。

一、闭包的使用

(一) 简单闭包的定义使用,当然闭包和方法意向,最后一个值默认为返回值
def closure={
    println "this is a closure"
}
closure.call()
closure()

结果:

this is a closure
this is a closure
(二) 闭包参数、默认参数、传参、指定参数

def closure={
    i="5",j->
    println "closure $i $j"
}
//map键值对会优先传给第一个参数,无论顺序,普通方法也是类似的
//有默认参数例外
closure('i':"5",'j':"10",5)
closure('i':"5",'j':"10")
closure("ja")
def newClosure = closure.ncurry(1,'6')
newClosure('7')

结果:

closure [i:5, j:10] 5
closure 5 [i:5, j:10]
closure 5 ja
closure 7 6
(三) 与接口互相替代
1、普通替代
interface  Ic{
    void call()
}

interface  IIc{
    void call()
}
def test(c){
    c()
}
def test2(IIc c){
    c()
}

test {
    println "closure"
}
test(new Ic(){

    @Override
    void call() {
        println "closure"
    }
})

test2{
    println "closure"
}

结果:

closure
closure
closure
2、多个方法替代

interface  IcTeste{
    void test1();
    void test2();
    void test3();
}

def test( c){
    c.test1();
    c.test2();
    c.test3();
}
def closure={
    println "test"
} as IcTeste
test(closure)

结果:

test
test
test

二、闭包的代理机制

closure有着独特的代理机制,我们戳进Closure这个类的时候,就会发现注释写的非常详细,而且还带有例子,直接看注释就能理解绝大部分内容了,良心呀,有例子的更能看明白,真的稳。
首先我看这段

* To be able to use a Closure in this way with your own
 * subclass, you need to provide a doCall method with any
 * signature you want to. This ensures that
 * {@link #getMaximumNumberOfParameters()} and
 * {@link #getParameterTypes()} will work too without any
 * additional code. 

其实这里稍微有点不明白,倒是是doCall还是call,实际上要用call方法才对呀,不过也不是重点了。我主要关注这两个方法,这两个方法就是获取闭包的参数个数以及类型了,直接测试一下。说实话我没有找到显示指定闭包参数类型的方法,有没有大神告知一下,万分感谢。

def c ={
    i ,j->
       println  "groovy $i $j"
}

println c.getMaximumNumberOfParameters()
println c.getParameterTypes()

结果:

2
[class java.lang.Object, class java.lang.Object]
代理的策略

闭包有三个变量,默认情况下
this 定义它的时候 所在的类的this 静态闭包当中为 class
owner 定义它的时候 所在类的对象
delegate 默认就是owner

使用delegate我们可以执行很多不同的操作,代理的策略总共有5个。

OWNER_FIRST 所有者优先
DELEGATE_FIRST 代理者优先
OWNER_ONLY 仅所有者
DELEGATE_ONLY 仅代理者
TO_SELF 仅自身

先看对于变量的影响。

class Test {
    def x = 30
    def y = 40

    def run() {
        def data = [x: 10, y: 20]
        def cl = { y = x + y }
        cl.delegate = data
        cl.resolveStrategy = Closure.DELEGATE_FIRST
        switch (cl.resolveStrategy) {
            case Closure.DELEGATE_FIRST:
                println "DELEGATE_FIRST"
                break;
            case Closure.DELEGATE_ONLY:
                println "DELEGATE_ONLY"
                break;
            case Closure.OWNER_ONLY:
                println "OWNER_ONLY"
                break;
            case Closure.TO_SELF:
                println "TO_SELF"
                break;
            case Closure.OWNER_FIRST:
                println "OWNER_FIRST"
                break;

        }
        println "cl=" + cl()
        println "x" + x
        println "y" + y
    }
}

new Test().run()

分别用5种策略测试结果

DELEGATE_FIRST|DELEGATE_ONLY
cl=30
x30
y40
===============================
OWNER_ONLY|OWNER_FIRST
cl=70
x30
y70
===============================
TO_SELF
Caught: groovy.lang.MissingPropertyException: No such property: x for class: Test$_run_closure1

一路看下来就很明确了,对于局部变量来说会根据策略的不同来选择,其实很简单。那么对于方法呢:

class Delegate {

    def fun() {
        println "delegate"
    }
}

def fun(){
    println "owner"
}
def cl = {
    def fun = {
        println "self"
    }
    fun()
}

cl.delegate = new Delegate()
cl.resolveStrategy = Closure.OWNER_FIRST
switch (cl.resolveStrategy) {
    case Closure.DELEGATE_FIRST:
        println "DELEGATE_FIRST"
        break;
    case Closure.DELEGATE_ONLY:
        println "DELEGATE_ONLY"
        break;
    case Closure.OWNER_ONLY:
        println "OWNER_ONLY"
        break;
    case Closure.TO_SELF:
        println "TO_SELF"
        break;
    case Closure.OWNER_FIRST:
        println "OWNER_FIRST"
        break;
}
cl()

这样写不管策略是什么,都会调用self,也就是局部变量是锁定了,我们把

    def fun = {
        println "self"
    }

这个闭包去掉,结果就不同了。

DELEGATE_FIRST|DELEGATE_ONLY
delegate
============================
OWNER_ONLY|OWNER_FIRST
owner
============================
TO_SELF
Caught: groovy.lang.MissingMethodException: No signature of method: test$_run_closure1.fun() is applicable for argument types: () values: []

闭包如果想要手动指定delegate,owner,this可以通过rehydrate(),该方法传递三个参数,分别对应delegate,owner,this。返回一个新的闭包来进行使用。

def fun(Closure c) {
    def b=c.rehydrate('123','234','456')
    b.call()
}


fun {
    println this
    println delegate
    println owner
}

结果:

456
123
234

利用这个特性,如果熟悉Gradle的人,就可以理解DSL的基本原理了。
那么闭包就总结到这里了,如果有错误欢迎在评论区指正。

展开阅读全文

没有更多推荐了,返回首页