在 kotlin 中使用字符串插值时跟踪注入的变量

keeping track of injected variables when using string interpolation in kotlin

我正在寻找一种方法来跟踪在不解析字符串的情况下进行字符串插值时使用的变量。例如,如果我有一个字符串:

val expStr = "${var1} some other useless text ${var2}"

我希望能够识别所用变量的 order,同样无需解析字符串。在这种情况下 [var1, var2] 将是预期的输出。到目前为止,我已经考虑定义一个 class ,我将所有变量传递给它。然后通过 class 函数 grab.

引用所述变量
val wrapper = ContainerClass(var1, var2)
val expStr = "${wrapper.grab(var1)} some other useless text ${wrapper.grab(var2)}"

里面ContainerClass是一个数组,每引用一个变量就加入数组,通过getReferenceCalls

输出
val whatIWant = wrapper.getReferenceCalls() // [var1, var2]

在我将字符串注入到字符串之前,这一直很好用。

val wrapper = ContainerClass(var1, var2, var3)
val snippet = "${wrapper.grab(var1)} some other useless text ${wrapper.grab(var2)}"
val expStr = "${wrapper.grab(var3)} ${snippet}"

val notWhatIWant = wrapper.getReferenceCalls() // [var1, var2, var3]

在这里,我想确定最终expStr中注入变量的顺序。 [变种 3、变种 1、变种 2]。我的问题是,如果不解析 expStr,这可能吗?我也确实想到了一个不太优雅的解决方案,允许我的 class 定义任何给定的“片段”,并且 class 标识片段中引用的变量。这行得通,但很快就会变得复杂。我真正需要的是一个优雅的解决方案...如果它存在的话。

我已经实现了一个“ContainerClass”来实现你的目标。我使用 String.format 而不是字符串模板,这样我就不需要输入的先验信息。

class StringNode(private val format: String, vararg args : Any) {
    private val argv = args

    override fun toString() : String = String.format(format,*argv)

    fun getFlatArgs() : List<Any> = argv.flatMap {
        if(it is StringNode){
            it.getFlatArgs()
        } else{
            listOf(it)
        }
    }
}

用法:

fun main(){
        val sn1 = StringNode("1:%s 2:%s 3:%s","abc",123,"def")
        println(sn1)
        println(sn1.getFlatArgs())

        val sn2 = StringNode("foo:%s bar:%s","foo",sn1);
        println(sn2)
        println(sn2.getFlatArgs())

        val sn3 = StringNode("sn1:%s, sn2:%s",sn1,sn2);
        println(sn3)
        println(sn3.getFlatArgs())
}

输出:

1:abc 2:123 3:def
[abc, 123, def]
foo:foo bar:1:abc 2:123 3:def
[foo, abc, 123, def]
sn1:1:abc 2:123 3:def, sn2:foo:foo bar:1:abc 2:123 3:def
[abc, 123, def, foo, abc, 123, def]
val var1 = "abc"
val var2 = "def"

val list = mutableListOf<String>()

val expStr = "${var1.also { list.add(it) }} some other useless text ${var2.also { list.add(it) }}"

println(expStr)   // Output: "abc some other useless text def"
println(list)     // Output: [abc, def]

或者:

val var1 = "abc"
val var2 = "def"

val list = mutableListOf<String>()
fun String.addTo(list: MutableList<String>) = this.also { list.add(it) }

val expStr = "${var1.addTo(list)} some other useless text ${var2.addTo(list)}"

println(expStr)   // Output: "abc some other useless text def"
println(list)     // Output: [abc, def]