2017-08-31 16 views
0

私はXML DSLをKotlinで記述しており、問題に直面しています。コード:KotlinのtoStringの再帰的な問題

abstract class Element(val name: String) { 

    var children = mutableListOf<Element>() 

    override fun toString() = """ 
     <$name> 
      ${children.joinToString("\n") { toString() }} 
     </$name> 
    """.trimIndent() 

} 

私は{ toString() }に次のエラーがあります。

型チェックは再帰的な問題に遭遇しました。最も簡単な回避策:宣言の種類を明示的に指定します。

私は次の出力が必要です

fun main(args: Array<String>) { 
    val a = Element("a") 
    a.children.add(Element("b")) 
    a.children.add(Element("c")) 
    println(a) 
} 

どのように私はこの問題を解決することができます:私は、次のコードをお持ちの場合

<a> 
    <b> 
    </b> 
    <c> 
    </c> 
</a> 

を?

答えて

1

ラムダ引数joinToStringからtoStringを呼び出すと、そのtoStringの受信者が指定されていませんでした。その場合、スコープ内の暗黙の受信者thisが使用されます。そのthisは現在の子ではなく親要素を指しているので、再帰呼び出しを行っています。

このラムダの中で、暗黙的なパラメータ名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