将 Kotlin 方法传递给 `javax.script.ScriptEngine`

最近我决定进入 Kotlin 并编写了一个玩具应用程序。我想使用 Kotlin 脚本接口扩展我的应用程序。

从中收集到的信息,我需要使用 6,这似乎也有效。我能够执行这样的脚本:

javax.script.ScriptEngine

这就像一个魅力。但是,我想进一步改进我的界面并省略 robot.configure { name = "FrankaPanda" } 调用。基本上,我想实现以下脚本:

configure

为了实现这一点,我认为“机器人”需要是一个接受 lambda 的函数。 但是,每当我尝试将方法绑定到 ScriptEngine

robot {
  name = "FrankaPanda"
}

我的脚本评估失败,出现异常:

javax.script.ScriptException:未解析的引用:机器人

我也尝试了其他几种方法,包括 val robot = Robot() scriptEngine.put("robot",robot::configure) 等,但都失败了。但是,我真的想省略显式调用 configure 并使我的界面更“Gradle-esque”。

问题

  • 如何使用 Kotlin 创建 Gradle 风格的脚本界面?
  • (奖励)Gradle 如何将任意“扩展”转换为接受 lambda 的函数?
zhuangting 回答:将 Kotlin 方法传递给 `javax.script.ScriptEngine`

好吧,我希望有更优雅的解决方案,但我找不到。

第一件事: 您不需要传递函数。一个可调用的类就足够了。当一个实例的类实现了操作符“invoke”时,它是可调用的。例如:

open class Extension {

   operator fun invoke() { /* ... */ }  

}

要通过(脚本)lambda 配置扩展,您需要扩展 invoke 函数以接受 lambda:

open class Extension {

   operator fun invoke(init: Extension.() -> Unit) {
     init(this)
   }  

}

但是,这个问题的前提是扩展本身没有实现操作符。相反,我想添加它们。定义扩展方法是行不通的,因为它受范围的限制。

这可以通过在脚本中定义扩展方法来避免:

type: Class<T>;

val code = """
    operator fun ${type.name}.invoke(init: ${type.name}.() -> Unit) {
        init(this)
    }
""".trimIndent()

scriptEngine.eval(code)
本文链接:https://www.f2er.com/809489.html

大家都在问