В чем разница между closureOf и delegateClosureOf в Gradle Kotlin DSL

В официальном документе говорится:

Иногда вам может потребоваться вызвать методы Groovy, которые принимают аргументы Closure из кода Kotlin. Например, некоторые сторонние плагины, написанные на Groovy, ожидают закрывающих аргументов.

Чтобы обеспечить способ создания замыканий при сохранении строгой типизации Kotlin, существуют два вспомогательных метода:

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

Оба метода полезны в разных обстоятельствах и зависят от метода, в который вы передаете экземпляр Closure. Некоторые плагины ожидают простого закрытия. В других случаях плагин ожидает закрытия делегата. Иногда по исходному коду невозможно определить, какую версию использовать. Обычно, если вы получаете NullPointerException с closureOf<T> {}, использование delegateClosureOf<T> {} решает проблему.

Что ж, у меня нет ничего против подхода «попробуй-сбой-исправь», но, может быть, есть детерминированный способ заранее сказать, какой метод использовать и почему?


person madhead    schedule 06.12.2018    source источник


Ответы (1)


но, возможно, есть детерминированный способ заранее сказать, какой метод использовать

Конечно, просто изучив исходный код настраиваемого плагина. Например, их пример плагина Bintray:

bintray {
    pkg(closureOf<PackageConfig> {
        // Config for the package here
    })
}

Если вы исследуете источник, вы найдете следующее: https://github.com/bintray/gradle-bintray-plugin/blob/master/src/main/groovy/com/jfrog/bintray/gradle/BintrayExtension.groovy#L35..L37

def pkg(Closure closure) {
    ConfigureUtil.configure(closure, pkg)
}

Это просто Closure, поэтому closureOf<T> {} здесь будет уместным в соответствии с документами.

Другой их пример - плагин Gretty при настройке ферм:

farms {
    farm("OldCoreWar", delegateClosureOf<FarmExtension> {
        // Config for the war here
    })
}

Если вы изучите источник, вы найдете следующее: 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()
  }

Это намного сложнее, чем в предыдущем примере, и, согласно документации, поскольку здесь явно ожидается закрытие делегата, подходящим выбором будет delegateClosureOf<T> {}.

person Francisco Mateo    schedule 14.06.2019