Kotlin中toString的递归问题

我用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) } 

我该如何解决这个问题?

当你从joinToString函数的lambda参数调用toString ,你没有指定toString的接收者。 在这种情况下,使用范围内的隐式接收器。 这指向父元素,而不是当前的孩子,所以你正在进行递归调用。

在那个lambda里面,你应该访问具有隐式参数名称的子元素,或者明确地命名参数。

 children.joinToString("\n") { it.toString() } children.joinToString("\n") { child -> child.toString() } 

但是,这不会使递归类型检查问题消失,因为这里同样的toString被引用在它的内部,其类型尚未被推断。 要打破这种递归,你需要明确指定toString的返回类型。

 override fun toString(): String = ... 

我是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) }