groovy闭包

243 阅读2分钟

为什么会开始学习闭包,因为在看到这个代码的时候我总是看不懂是什么意思:

gradle.taskGraph.beforeTask {
    println("任务之前执行")
}
gradle.taskGraph.afterTask {Task task,TaskState state->
    println("任务之后执行")
}

这里你可以点开源码,比如这个afterTask:

class TaskExecutionGraph{
    void beforeTask(Closure var1);
    void beforeTask(Action<Task> var1);
    void afterTask(Closure var1);
    void afterTask(Action<Task> var1);
}

这里可以看到传入的参数是一个叫Closure的类,这个就是Groovy里面的闭包.
这里举个闭包的例子:

//lala.gradle
class Person{
    String getName(Closure closure){
        closure("cc","dd")
    }
}
def bibao = {
    x , y -> 
        println("Hello Closure ,the param valus is: "+x+","+y)
}
new Persion().getName(bibao)

// 运行后输出:
Hello Closure ,the param valus is:cc,dd

上面的也可以这么写:

class Person{
    String getName(Closure closure){
        closure("cc","dd")
    }
}
new Persion().getName{x,y->
    println("Hello Closure ,the param valus is: "+x+","+y)
}

看了上面这个例子你对闭包应该了解了,和kotlin里面的闭包差不多. 闭包


再回到上面的代码:

gradle.taskGraph.afterTask {Task task,TaskState state->
    println("任务之后执行")
}

我们在看到源码的时候,看到的是afterTask里面传的参数是Closure,也就是一个闭包,那我们怎么知道这个闭包到底该怎么写呢.这个时候就需要看官方文档了:docs.gradle.org/current/jav…
找到afterTask方法: captrue.png 可以看到官方文档写清楚了,他的参数有哪些.


现在看另外一个方法: (这个方法是用来配置远程仓库的)

repositories {
    mavenCentral()
}
class Project{
    void repositories(Closure var1);
}

可以看到这个方法是属于project对象的.
打开官方文档找下这个方法:

captrue.png

文档里面很清楚的讲了RepositoryHandler做为闭包的委托传递给闭包.

这里出现了一个新的知识点做为闭包的委托传递给闭包.
闭包委托:
groovy的闭包委托有thisObject,owner,delegate三个属性.当在闭包内调用方法时,由他们来确定使用哪个对象来处理.默认情况owner和delegeta是相等的.但是delegate是可以进行修改的.

//闭包委托
def method1(){
    println "Context this :${this.getClass()} in root"
    println "method1 in root"
}

class Delegate{
    def method1(){
        println "Delegate this : ${this.getClass()} in Delegate"
        println "method1 in Delegate"
    }

    def test(Closure<Delegate> closure){
            closure(this)
    }
}

task helloDelegate <<{
    new Delegate().test{
        println "thisObject :${thisObject.getClass()}"
        println "owner:${owner.getClass()}"
        println "delegate:${delegate.getClass()}"
        method1()
        it.method1()
    }
}
//输出
thisObject :class build_apnm7l2hrtoaa0bd51bpb5xcf
owner:class build_apnm7l2hrta
delegate:class build_apnm7
Context this :class build_apnm7l2hrtoaa0bd51bpb5xcf in root
method1 in root
Delegate this : class Delegate in Delegate
method1 in Delegate

可以看到thisObject优先级是最高的.
在DSL中,比如gradle,一般会指定delegate为当前it,这样我们就可以在闭包中对该it进行配置和方法调用:

class Person {
    String personName
    int personAge

    def dumpPerson(){
        println "name is ${personName}, age is ${personAge}"
    }
}

def person(Closure<Person> closure){
    Person p = new Person()
    closure.delegate = p
    //委托模式优先
    closure.setResolveStrategy(Closure.DELEGATE_FIRST)
    closure(p)
}

task configClosure << {
    person{
        personName="张三"
        personAge = 20
        dumpPerson()
    }
}

在回到上面讲的方法:

repositories {
    mavenCentral()
}

官方文档讲了RepositoryHandler做为了闭包的委托传递给了闭包,所以在{}里面可以用到的方法就都是在RepositoryHandler对象申明的方法了.不信你可以打开RepositoryHandler类看下:

public interface RepositoryHandler extends ArtifactRepositoryContainer {
    FlatDirectoryArtifactRepository flatDir(Map<String, ?> var1);

    FlatDirectoryArtifactRepository flatDir(Closure var1);

    FlatDirectoryArtifactRepository flatDir(Action<? super FlatDirectoryArtifactRepository> var1);

    ArtifactRepository gradlePluginPortal();

    ArtifactRepository gradlePluginPortal(Action<? super ArtifactRepository> var1);

    /** @deprecated */
    @Deprecated
    MavenArtifactRepository jcenter(Action<? super MavenArtifactRepository> var1);

    /** @deprecated */
    @Deprecated
    MavenArtifactRepository jcenter();

    MavenArtifactRepository mavenCentral(Map<String, ?> var1);

    MavenArtifactRepository mavenCentral();

    MavenArtifactRepository mavenCentral(Action<? super MavenArtifactRepository> var1);

    MavenArtifactRepository mavenLocal();

    MavenArtifactRepository mavenLocal(Action<? super MavenArtifactRepository> var1);

    MavenArtifactRepository google();

    MavenArtifactRepository google(Action<? super MavenArtifactRepository> var1);

    MavenArtifactRepository maven(Closure var1);

    MavenArtifactRepository maven(Action<? super MavenArtifactRepository> var1);

    IvyArtifactRepository ivy(Closure var1);

    IvyArtifactRepository ivy(Action<? super IvyArtifactRepository> var1);

    void exclusiveContent(Action<? super ExclusiveContentRepository> var1);
}

是不是看到了我们熟知的方法:jcenter mavenCentral.所以上面的代码完整点可以这么写:

repositories {RepositoryHandler->
    RepositoryHandler.mavenCentral()
}