We can easily nest expression operators like if
and when
in Kotlin string templates:
"List ${if (list.isEmpty()) "is empty" else "has ${list.size} items"}."
But for
or while
are not expressions and can't be nested in template like this:
"<ol>${for (item in list) "<li>$item"}</ol>"
So I was looking for convinient ways to use loops inside large templates.
The easiest out-of-the-box way I found so far is to replace loops with equivalent joinToString calls:
"<ol>${list.joinToString("") { "<li>$it" }}</ol>"
or
"""
<ol>${list.indices.joinToString("") {
"""
<li id="item${it + 1}">${list[it]}"""
}}
</ol>""".trimIndent()
In the matter of preference, it's also possible to simulate loops with helper functions:
inline fun <T> forEach(iterable: Iterable<T>, crossinline out: (v: T) -> String)
= iterable.joinToString("") { out(it) }
fun <T> forEachIndexed1(iterable: Iterable<T>, out: (i: Int, v: T) -> String): String {
val sb = StringBuilder()
iterable.forEachIndexed { i, it ->
sb.append(out(i + 1, it))
}
return sb.toString()
}
and use them like this:
"<ol>${forEach(list) { "<li>$it" }}</ol>"
or
"""
<ol>${forEachIndexed1(list) { i, item ->
"""
<li id="item$i">$item"""
}}
</ol>""".trimIndent()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With