3

ノード構造に再帰的なトラバージョンを実装しようとしています。

sealed class Node(subnodes: Traversable[Node]) extends Traversable[Node] {
  def foreach[U](f: Node => U) {
    f(this)
    subnodes foreach f
  }
}

case class Atom(id: String) extends Node(Nil)

case class Molecule(atoms: List[Node]) extends Node(atoms)

toStringのような要素を呼び出すAtom("test").toStringと、スタックオーバーフローが発生します。

Exception in thread "main" java.lang.StackOverflowError
at java.lang.System.arraycopy(Native Method)
at java.lang.String.getChars(Unknown Source)
at java.lang.AbstractStringBuilder.append(Unknown Source)
at java.lang.StringBuilder.append(Unknown Source)
at scala.collection.mutable.StringBuilder.append(StringBuilder.scala:197)
at scala.collection.TraversableOnce$class.addString(TraversableOnce.scala:297)
at Node.addString(Fail.scala:1)
at scala.collection.TraversableOnce$class.mkString(TraversableOnce.scala:263)
at Node.mkString(Fail.scala:1)
at scala.collection.TraversableLike$class.toString(TraversableLike.scala:615)
at Node.toString(Fail.scala:1)
at java.lang.String.valueOf(Unknown Source)
at scala.collection.mutable.StringBuilder.append(StringBuilder.scala:187)
at scala.collection.TraversableOnce$$anonfun$addString$1.apply(TraversableOnce.scala:300)
[...]
at Node.foreach(Fail.scala:3)
at scala.collection.TraversableOnce$class.addString(TraversableOnce.scala:298)
at Node.addString(Fail.scala:1)
at scala.collection.TraversableOnce$class.mkString(TraversableOnce.scala:263)
at Node.mkString(Fail.scala:1)
at scala.collection.TraversableLike$class.toString(TraversableLike.scala:615)
at Node.toString(Fail.scala:1)
at java.lang.String.valueOf(Unknown Source)
at scala.collection.mutable.StringBuilder.append(StringBuilder.scala:187)
at scala.collection.TraversableOnce$$anonfun$addString$1.apply(TraversableOnce.scala:300)

foreachを明示的に呼び出していないことに注意してください。では、なぜスタックオーバーフローが発生するのですか?

この特定の問題を追加のクラスとからへTraversableNodeの暗黙の変換で解決しましたが、スタックオーバーフローの原因を知りたいと思います。ありがとう。NodeTraversableNode

4

2 に答える 2

5

を呼び出すtoString、ドキュメントでは次のように説明されてAtomいる のものが取得されます。Traversable

デフォルトでは、この文字列はstringPrefixこのコレクションの で構成され、その後にコンマで区切られ、括弧で囲まれたすべての要素が続きます。

「すべての要素が続く」部分は、コレクションの を呼び出すことで実装TraversableOnceforeachれます。最初に自分自身にforeachヒットしたためNode、すぐに無限ループに陥ります。

于 2012-08-20T12:23:44.997 に答える
1

通常、toStringケース クラスのメソッドは、クラス名とその引数のリスト (最初の引数リストにあるもの) を出力します。ケース クラスが明示的に定義されtoStringた .

あなたのNode拡張Traversable[Node]. toStringAST ( scalac -Xprint:cleanup)に示されているように、コンパイラによって生成された case-class がないことに注意してください。

case class Atom extends Node with Product with Serializable {
   ....
    override <synthetic> def hashCode(): Int = ScalaRunTime.this._hashCode(Atom.this);
    override <synthetic> def equals(x$1: Any): Boolean = Atom.this.eq(x$1.asInstanceOf[Object]()).||(x$1.isInstanceOf[Atom]().&&({
      <synthetic> val Atom$1: Atom = x$1.asInstanceOf[Atom]();
      Atom.this.id().==(Atom$1.id()).&&(Atom$1.canEqual(Atom.this))
    }))
  };

上記では、コンパイラは "のみ" を生成hashCodeequalstoStringは から継承されTraversableます。

パッケージのTraversabletrait には、で定義されたメソッドがあります。このように呼び出すと、ノード自体で ( に沿って) 反復処理が行われ、無限ループが発生します。collectiontoStringforeachtoStringforeachf(this)

于 2012-08-20T12:17:24.090 に答える