假设我有以下Kotlin代码:
fun main(args: Array<String>) {
val a = "test"
println(args.first())
}
如果我传入参数$a
,则输出将为$a
。据我所知,Kotlin通过在编译时生成输出代码来处理String模板,可能是使用StringBuilder。有没有办法在当前上下文中评估关于模板的源代码中没有的字符串?字符串模板非常有用,能够评估来自动态上下文的表达式(例如配置文件)会很棒,但据我所知,这是不可能的。
缺乏这一点,对此有什么好处?调用脚本引擎?
答案 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
针对此限制有多种解决方法:
您可以将 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, ...)
之类的内容,其中template
为String
,如"$a"
和arg1,arg2,...是模板的参数?
如果是这样,那么没有特定于Kotlin的方法,但您可以使用Java Formatter类。