Kotlin и Groovy оба предоставляют способ написать функцию высокого порядка, где параметр функции имеет неявный получатель.
Kotlin Version
class KotlinReceiver {
fun hello() {
println("Hello from Kotlin")
}
}
class KotlinVersion {
fun withReceiver(fn: KotlinReceiver.() -> Unit) {
KotlinReceiver().fn()
}
}
// And then I can call...
val foo = KotlinVersion()
foo.withReceiver { hello() }
Groovy Version
class GroovyReceiver {
void hello() {
println("Hello from Groovy")
}
}
class GroovyVersion {
void withReceiver(Closure fn) {
fn.resolveStrategy = Closure.DELEGATE_FIRST
fn.delegate = new GroovyReceiver()
fn.run()
}
}
// And then I can call...
def foo = new GroovyVersion()
foo.withReceiver { hello() }
Моя цель - написать функцию withReceiver
на Kotlin, но вызывать ее из groovy и получить { hello() }
work. Однако, как написано, Kotlin генерирует байт-код, такой как
public final void withReceiver(@NotNull Function1 fn) { /* ... */ }
, который Groovy рассматривает как функцию с параметром. Другими словами, чтобы позвонить Котлину withReceiver
из Groovy, я должен сделать это:
(new KotlinVersion()).withReceiver { it -> it.hello() }
Чтобы разрешить { hello() }
без it -> it.
, я должен добавить перегрузку, которая принимает groovy.lang.Closure
в качестве параметра.
Kotlin Version
import groovy.lang.Closure
class KotlinVersion {
fun withReceiver(fn: KotlinReceiver.() -> Unit) {
KotlinReceiver().fn()
}
fun withReceiver(fn: Closure<Any>) = withReceiver {
fn.delegate = this
fn.resolveStrategy = Closure.DELEGATE_FIRST
fn.run()
}
}
С учетом этой перегрузки, учитывая экземпляр KotlinVersion
с именем foo
, следующая строка работает на обоих языках:
// If this line appears in Groovy code, it calls the Closure overload.
// If it's in Kotlin, it calls the KotlinReceiver.() -> Unit overload.
foo.withReceiver { hello() }
Я пытаюсь сохранить этот синтаксис, но избегайте необходимости писать дополнительную шаблонную перегрузку для каждой функции высокого порядка, которую определяет моя библиотека Kotlin. Есть ли лучший (более простой / автоматический) способ сделать синтаксис функции с приемником Kotlin доступным из Groovy, поэтому мне не нужно вручную добавлять шаблонную перегрузку для каждой из моих функций Kotlin?
Полный код и инструкции по компиляции для моего игрушечного примера выше: на gitlab .