Cómo incrustar los loops en las templates de cadenas de Kotlin

Podemos jerarquizar fácilmente los operadores de expresiones como if y en las templates de cadenas de Kotlin:

 "List ${if (list.isEmpty()) "is empty" else "has ${list.size} items"}." 

Pero for o while no son expresiones y no pueden anidarse en una plantilla como esta:

 "<ol>${for (item in list) "<li>$item"}</ol>" 

Así que estaba buscando forms convenientes de usar loops dentro de templates grandes.

Solutions Collecting From Web of "Cómo incrustar los loops en las templates de cadenas de Kotlin"

La manera más fácil de usarlo que encontré hasta ahora es replace los loops con llamadas joinToString equivalentes:

 "<ol>${list.joinToString("") { "<li>$it" }}</ol>" 

o

 """ <ol>${list.indices.joinToString("") { """ <li id="item${it + 1}">${list[it]}""" }} </ol>""".trimIndent() 

En materia de preference, también es posible simular loops con funciones de ayuda:

 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() } 

y utilícelos así:

 "<ol>${forEach(list) { "<li>$it" }}</ol>" 

o

 """ <ol>${forEachIndexed1(list) { i, item -> """ <li id="item$i">$item""" }} </ol>""".trimIndent() 

simplemente puede usar joinToString .

 val s = """<ol> ${list.joinToString { "<li>$it</li>" }} </ol>"""; 

Salida

 <ol> <li>one</li> <li>two</li> ... </ol>