Kotlin和Groovy都提供了一种在函数参数具有隐式接收器的情况下编写高阶函数的方法。
科林版本
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
函数,但从常规上调用它并运行{ 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
作为参数的重载。
科林版本
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
的{{1}}实例,以下行就可以在两种语言中工作:
foo
我正在尝试保留这种语法,但要避免为Kotlin库定义的每个高阶函数编写额外的样板重载。是否有一种更好的(更无缝/自动)的方法可以使Groovy使用Kotlin的带接收器的语法,因此我不必为每个Kotlin函数手动添加样板过载?
上面我的玩具示例的完整代码和编译说明为on gitlab。
答案 0 :(得分:1)
在Groovy中,您可以动态定义新功能
KotlinVersion.metaClass.withReceiver = { Closure c->
delegate.with(c)
}
这将为类withReceiver
定义新功能KotlinVersion
,并将允许将此语法用于KotlinVersion
实例:
kv.withReceiver{ toString() }
在这种情况下,toString()
将在kv
上被调用
您可以编写使用kotlin.Function
参数通过kotlin类的声明方法进行迭代的函数,并通过metaClass使用groovy.lang.Closure
参数声明新方法。