2017-08-31 77 views
0

我用Kotlin编写XML DSL并遇到问题。代码:Kotlin的toString递归问题

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

我怎样才能解决这个问题?

回答

1

当您从joinToString函数的lambda参数调用toString时,您并未指定该toString的接收方。在这种情况下,使用范围内的隐式接收器thisthis指向父元素而不是当前子元素,因此您正在进行递归调用。

在那个lambda中,您应该访问带有隐式参数名称it的子元素,或者明确地命名参数。

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

然而,这不会使递归类型检查问题消失,因为这里同样toString是其体内引用,其类型尚未推断。要打破这种递归,您需要明确指定返回类型toString

override fun toString(): String = ... 
+0

谢谢!现在我有'StackOverflowError',但我认为这是另一回事;) – Feeco

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) 
} 
+0

谢谢,它的工作原理!我建议你阅读[字符串插值](https://kotlinlang.org/docs/reference/idioms.html#string-interpolation)。 – Feeco