Gradle Kotlin DSL 中的closureOf 和 delegateClosureOf 有什么区别

mad*_*ead 5 closures gradle kotlin gradle-kotlin-dsl

官方文档说:

有时您可能需要调用从 Kotlin 代码获取闭包参数的 Groovy 方法。例如,一些用 Groovy 编写的第三方插件需要闭包参数。

为了提供一种在保留 Kotlin 强类型的同时构造闭包的方法,存在两种辅助方法:

  • closureOf<T> {}
  • delegateClosureOf<T> {}

这两种方法在不同的情况下都很有用,并且取决于您将Closure实例传递到的方法。一些插件期望简单的闭包。在其他情况下,插件需要委托关闭。有时,通过查看源代码,无法判断要使用哪个版本。通常,如果您使用NullPointerExceptionwith closureOf<T> {},使用delegateClosureOf<T> {}将解决问题。

好吧,我不反对尝试失败修复方法,但也许有一种确定性的方法可以提前告诉使用哪种方法以及为什么?

Fra*_*teo 3

但也许有一种确定性的方法可以提前告诉使用哪种方法

当然,只需检查您正在配置的插件的源代码即可。例如,他们的 Bintray 插件示例是:

bintray {
    pkg(closureOf<PackageConfig> {
        // Config for the package here
    })
}
Run Code Online (Sandbox Code Playgroud)

如果您要检查源代码,您会发现:https: //github.com/bintray/gradle-bintray-plugin/blob/master/src/main/groovy/com/jfrog/bintray/gradle/BintrayExtension。绝妙#L35..L37

def pkg(Closure closure) {
    ConfigureUtil.configure(closure, pkg)
}
Run Code Online (Sandbox Code Playgroud)

这很简单 Closure,所以closureOf<T> {}根据文档在这里是合适的。

现在他们的另一个例子是配置农场时的 Gretty 插件:

farms {
    farm("OldCoreWar", delegateClosureOf<FarmExtension> {
        // Config for the war here
    })
}
Run Code Online (Sandbox Code Playgroud)

如果您检查源代码,您会发现:https: //github.com/akhikhl/gretty/blob/master/libs/gretty-core/src/main/groovy/org/akhikhl/gretty/FarmsConfig.groovy# L23..L32

  void farm(String name = null, Closure closure) {
    if(name == null)
      name = ''
    def f = farmsMap_[name]
    if(f == null)
      f = farmsMap_[name] = createFarm()
    closure.delegate = f
    closure.resolveStrategy = Closure.DELEGATE_FIRST
    closure()
  }
Run Code Online (Sandbox Code Playgroud)

根据文档,这比前面的示例要复杂得多,因为这显然需要委托关闭,所以这delegateClosureOf<T> {} 将是适当的选择。