带接收器的 Kotlin 函数参数,从 Groovy 调用
Kotlin function parameter with receiver, called from Groovy
Kotlin 和 Groovy 都提供了一种编写高阶函数的方法,其中函数参数具有隐式接收者。
Kotlin 版本
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版本
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() }
我的目标是在 Kotlin 中编写 withReceiver
函数,但从 groovy 调用它并让 { hello() }
工作。但是,正如所写的那样,Kotlin 生成的字节码类似于
public final void withReceiver(@NotNull Function1 fn) { /* ... */ }
其中 Groovy 将其视为带参数的函数。换句话说,要从 Groovy 调用 Kotlin 的 withReceiver
,我必须这样做:
(new KotlinVersion()).withReceiver { it -> it.hello() }
为了允许 { hello() }
没有 it -> it.
,我必须添加一个以 groovy.lang.Closure
作为参数的重载。
Kotlin 版本
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()
}
}
有了这个重载,给定一个名为 foo
的 KotlinVersion
实例,以下行适用于两种语言:
// 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 库定义的每个高阶函数编写额外的样板重载。是否有更好的(更多 seamless/automatic)方法使 Kotlin 的带有接收器的函数语法在 Groovy 中可用,这样我就不必手动为我的每个 Kotlin 函数添加样板重载?
上面我的玩具示例的完整代码和编译说明是on gitlab。
在groovy中你可以动态定义新函数
KotlinVersion.metaClass.withReceiver = { Closure c->
delegate.with(c)
}
这将为 class KotlinVersion
定义新函数 withReceiver
并将允许将此语法用于 KotlinVersion
实例:
kv.withReceiver{ toString() }
在这种情况下 toString()
将在 kv
上调用
您可以使用 kotlin.Function
参数编写循环遍历 kotlin class 声明方法的函数,并通过 metaClass 使用 groovy.lang.Closure
参数声明新方法。
Kotlin 和 Groovy 都提供了一种编写高阶函数的方法,其中函数参数具有隐式接收者。
Kotlin 版本
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版本
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() }
我的目标是在 Kotlin 中编写 withReceiver
函数,但从 groovy 调用它并让 { hello() }
工作。但是,正如所写的那样,Kotlin 生成的字节码类似于
public final void withReceiver(@NotNull Function1 fn) { /* ... */ }
其中 Groovy 将其视为带参数的函数。换句话说,要从 Groovy 调用 Kotlin 的 withReceiver
,我必须这样做:
(new KotlinVersion()).withReceiver { it -> it.hello() }
为了允许 { hello() }
没有 it -> it.
,我必须添加一个以 groovy.lang.Closure
作为参数的重载。
Kotlin 版本
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()
}
}
有了这个重载,给定一个名为 foo
的 KotlinVersion
实例,以下行适用于两种语言:
// 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 库定义的每个高阶函数编写额外的样板重载。是否有更好的(更多 seamless/automatic)方法使 Kotlin 的带有接收器的函数语法在 Groovy 中可用,这样我就不必手动为我的每个 Kotlin 函数添加样板重载?
上面我的玩具示例的完整代码和编译说明是on gitlab。
在groovy中你可以动态定义新函数
KotlinVersion.metaClass.withReceiver = { Closure c->
delegate.with(c)
}
这将为 class KotlinVersion
withReceiver
并将允许将此语法用于 KotlinVersion
实例:
kv.withReceiver{ toString() }
在这种情况下 toString()
将在 kv
您可以使用 kotlin.Function
参数编写循环遍历 kotlin class 声明方法的函数,并通过 metaClass 使用 groovy.lang.Closure
参数声明新方法。