动态评估Kotlin中的模板化字符串

G_H*_*G_H 2 templates dynamic kotlin

假设我有以下Kotlin代码:

fun main(args: Array<String>) {
    val a = "test"
    println(args.first())
}
Run Code Online (Sandbox Code Playgroud)

如果我传入一个参数$a,输出将是$a.据我了解,Kotlin通过在编译时生成输出代码来处理String模板,可能是使用StringBuilder.有没有办法在当前上下文中评估关于模板的源代码中没有的字符串?字符串模板非常有用,能够评估来自动态上下文的表达式(例如配置文件)会很棒,但据我所知,这是不可能的.

缺乏这一点,对此有什么好处?调用脚本引擎?

Mic*_*hli 14

为了完整起见,这里还提供了一些在 Kotlin 代码中动态评估字符串模板的方法。

字符串模板的正常行为是在编译时评估字符串的内容。在代码执行期间它不会改变:

fun main() {
    var subject = "world"
    val hello = "hello $subject"

    subject = "stackoverflow"
    println(hello)
}

// Output: hello world
Run Code Online (Sandbox Code Playgroud)

针对此限制有多种解决方法:

拉姆达函数

您可以将 String 包装在 lambda 函数中,因此每次调用函数时,它都会评估 String 的新实例。

fun main() {
    var subject = "world"
    val hello = {"hello $subject"}

    subject = "stackoverflow"
    println(hello())
}

// Output: hello stackoverflow
Run Code Online (Sandbox Code Playgroud)

优势

  • 支持字符串操作

坏处

  • 必须像函数一样调用它

匿名对象

您可以创建匿名对象(类似于Java中的static)并重写toString方法。

fun main() {
    var subject = "world"
    val hello = object { override fun toString() = "hello $subject"}

    subject = "stackoverflow"
    println(hello())
}
    
// Output: hello stackoverflow
Run Code Online (Sandbox Code Playgroud)

注意:我不推荐这种方法。

优势

  • 无需函数调用

坏处

  • 不支持所有字符串操作

财产委托

您可以将属性运算符函数委托给外部类,以实现 String 模板的动态计算。

import kotlin.reflect.KProperty

fun main() {
    var subject = "world"
    val hello: String by dynamicStringTemplate { "hello $subject" }

    subject = "stackoverflow"
    println(hello)
}

// Output: hello stackoverflow
 
class dynamicStringTemplate(var value: () -> String) {
    operator fun getValue(thisRef: Nothing?, prop: KProperty<*>): String {       
        return this.value()
    }
 
    operator fun setValue(thisRef:  Nothing?, prop: KProperty<*>, value: String) {
        this.value = {value}
    }
}
Run Code Online (Sandbox Code Playgroud)

优点

  • 支持所有字符串操作
  • 与字符串的工作方式相同

坏处

  • 必须创建额外的类


hot*_*key 9

如果您需要以这种方式评估任意表达式,那么是的,您需要一个脚本引擎.Kotlin有一个可以使用的JSR 223实现,请参阅此处kotlin-jsr223-*的示例(项目).

这是一个基本的用法示例:

val engine = ScriptEngineManager().getEngineByExtension("kts")!!
engine.eval("val x = 3")
val res = engine.eval("x + 2")
Assert.assertEquals(5, res)
Run Code Online (Sandbox Code Playgroud)

代码取自KotlinJsr223ScriptEngineIT.kt,并记得通过配置服务META-INF