我用Kotlin编写XML DSL并遇到了问题。代码:
abstract class Element(val name: String) {
var children = mutableListOf<Element>()
override fun toString() = """
<$name>
${children.joinToString("\n") { toString() }}
</$name>
""".trimIndent()
}
我在{ toString() }
上有以下错误:
类型检查遇到了递归问题。最简单的解决方法:明确指定声明的类型。
我需要以下输出:
<a>
<b>
</b>
<c>
</c>
</a>
如果我有以下代码:
fun main(args: Array<String>) {
val a = Element("a")
a.children.add(Element("b"))
a.children.add(Element("c"))
println(a)
}
我该如何解决这个问题?
答案 0 :(得分:1)
当您从toString
函数的lambda参数调用joinToString
时,您没有指定toString
的接收者。在这种情况下,使用范围中的隐式接收器this
。 this
指向父元素而不是当前子元素,因此您正在进行递归调用。
在lambda中你应该使用隐式参数名it
访问子元素,或者明确命名参数。
children.joinToString("\n") { it.toString() }
children.joinToString("\n") { child -> child.toString() }
然而,这不会使递归类型检查问题消失,因为这里在其主体内引用相同的toString
,其类型尚未被推断。要打破这种递归,您需要明确指定toString
的返回类型。
override fun toString(): String = ...
答案 1 :(得分:1)
我是Kotlin的新手,所以这可能不是非常惯用的。但它确实有用。
class Element(val name: String) {
var children = mutableListOf<Element>()
private fun recursiveToString(depth: Int): String {
fun tabulations(amount: Int) = "\t".repeat(amount)
val childrenAsString: String = children.joinToString("") {
tabulations(depth + 1) + it.recursiveToString(depth + 1)
}
return "<$name>\n$childrenAsString${tabulations(depth)}</$name>\n"
}
override fun toString() = recursiveToString(0)
}
fun main(args: Array<String>) {
val a = Element("a")
a.children.add(Element("b"))
val c = Element("c")
c.children.add(Element("d"))
a.children.add(c)
println(a)
}