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

时间:2017-05-16 19:00:33

标签: templates dynamic kotlin

假设我有以下Kotlin代码:

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

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

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

3 个答案:

答案 0 :(得分:8)

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

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

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

代码来自KotlinJsr223ScriptEngineIT.kt,请记住configure the service via META-INF

答案 1 :(得分:2)

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

String 模板的正常行为是在编译时评估 String 的内容。它不会在您的代码执行期间发生变化:

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

    subject = "stackoverflow"
    println(hello)
}

// Output: hello world

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

Lambda 函数

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

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

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

// Output: hello stackoverflow

优势

  • 支持字符串操作

缺点

  • 必须像函数一样调用它

匿名对象

您可以创建匿名对象(类似于 Java 中的静态对象)并覆盖 toString 方法。

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

    subject = "stackoverflow"
    println(hello())
}
    
// Output: hello stackoverflow

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

优势

  • 不需要函数调用

缺点

  • 不支持所有字符串操作

属性委托

您可以将属性运算符函数委托给外部类,以实现对 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}
    }
}

优势

  • 支持所有字符串操作
  • 与字符串相同

缺点

  • 必须创建额外的类

答案 2 :(得分:0)

  

有没有办法评估源代码中关于模板的字符串当前上下文中的字符串?

您的代码示例中没有模板字符串,a未使用。我是否正确理解您希望执行val evaluated = evalStringTemplate(template, arg1, arg2, ...)之类的内容,其中templateString,如"$a"和arg1,arg2,...是模板的参数?

如果是这样,那么没有特定于Kotlin的方法,但您可以使用Java Formatter类。