Scala 可遍历递归节点结构
我试图在节点结构上实现递归遍历:Scala 可遍历递归节点结构,scala,foreach,stack-overflow,tostring,case-class,Scala,Foreach,Stack Overflow,Tostring,Case Class,我试图在节点结构上实现递归遍历: 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[N
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
(“测试”)。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
类和从Node
到TraversableNode
的隐式转换解决了这个特殊问题,但我仍然想知道是什么导致了堆栈溢出。谢谢。通常情况下,case类上的toString
方法会打印类名及其参数列表(第一个参数列表中的参数)。如果您的case类扩展了一个具有显式定义的toString
的类,则此规则有一个例外
您的节点
扩展了可遍历的[Node]
。请注意,它没有编译器生成的case类toString
,如其AST(scalac-Xprint:cleanup
)所示:
case类Atom使用可序列化的产品扩展节点{
....
重写def hashCode():Int=ScalaRunTime.this.\u hashCode(Atom.this);
override def equals(x$1:Any):Boolean=Atom.this.eq(x$1.asInstanceOf[Object]())。| |(x$1.isInstanceOf[Atom]()&&({
val Atom$1:Atom=x$1.asInstanceOf[Atom]();
Atom.this.id()。==(Atom$1.id())&&(Atom$1.canEqual(Atom.this))
}))
};
上面,编译器“仅”生成hashCode
和等于,toString
从可遍历的继承
来自集合
包的travelable
trait有一个toString
方法,该方法是根据foreach
定义的。调用toString
会使foreach
在节点本身上迭代(与f(this)
一致),从而产生一个无限循环。在原子上调用toString
时,您得到的是可遍历的,如下所述:
默认情况下,此字符串由该字符串的stringPrefix
组成
集合,后跟所有元素,元素之间用逗号分隔并封闭
括号内
“后跟所有元素”部分通过调用集合的foreach
来实现。由于您的foreach
首先命中节点本身,因此您会立即陷入一个无休止的循环
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))
}))
};