For completeness, here are also some ways to dynamically evaluate String templates in your Kotlin code.
The normal behavior of String templates is to evaluate the contents of the String at compile time. It will not change during the execution of your code:
fun main() {
var subject = "world"
val hello = "hello $subject"
subject = "stackoverflow"
println(hello)
}
// Output: hello world
There are multiple workarounds for this restriction:
Lambda function
You can wrap your String in a lambda function, so everytime you call your function, it will evaluate a new instance of the String.
fun main() {
var subject = "world"
val hello = {"hello $subject"}
subject = "stackoverflow"
println(hello())
}
// Output: hello stackoverflow
Advantage
- Support String operations
Disadvantage
- Must call it like a function
Anonymous object
You can create anonymous objects (similar to static in Java) and override the toString method.
fun main() {
var subject = "world"
val hello = object { override fun toString() = "hello $subject"}
subject = "stackoverflow"
println(hello())
}
// Output: hello stackoverflow
Note: I would not recommend this approach.
Advantage
Disadvantage
- Does not support all String operations
Property Delegation
You can delegate property operator functions to an external class to achieve the dynamic evaluation of String templates.
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}
}
}
Advantages
- Supports all String operations
- Works the same as a String
Disadvantage
- Additional class must be created