2017-07-03 39 views
1

我想实现一个链表的迭代。但是这个实现会引发堆栈溢出错误。我在这里做错了什么?为什么这个可迭代的实现会产生一个stackoverflow?

即使在我调用该类的任何函数之前,iterable实现仍会抛出错误。

我最初认为,这可能是因为使用def而不是VAL为nodeValue和tailList。但是这并没有解决问题。

我试图将迭代器更改为遍历Int而不是LinkedList。我仍然得到同样的错误。 在此先感谢!

trait LinkedList extends Iterable[LinkedList]{ 
    def nodeValue: Int 
    def tailList: LinkedList 
} 

class Node(val nodeValue: Int, val tailList: LinkedList) extends LinkedList { 

    override def iterator: Iterator[LinkedList] = Iterator 
    .iterate(this: LinkedList)(_.tailList) 
    .takeWhile(_ != Nil) 
} 

object Nil extends LinkedList { 
    def nodeValue= throw new IllegalAccessException("head of Nil") 
    def tailList = throw new IllegalAccessException("tail of Nil") 

    override def iterator: Iterator[LinkedList] = Iterator.empty 
} 

val singleLinkedList = new Node(1,Nil) 
val chainedLinkedList = new Node(2,singleLinkedList) 

//Printing this first Time 
//chainedLinkedList.foreach(println) 

输出:

java.lang.StackOverflowError 
    at scala.collection.AbstractIterable.<init>(LinkedListIterable.sc:50) 
    at scala.collection.AbstractSeq.<init>(LinkedListIterable.sc:37) 
    at scala.collection.mutable.AbstractSeq.<init>(LinkedListIterable.sc:44) 
    at scala.collection.mutable.StringBuilder.<init>(LinkedListIterable.sc:28) 
    at scala.collection.mutable.StringBuilder.<init>(LinkedListIterable.sc:45) 
    at scala.collection.mutable.StringBuilder.<init>(LinkedListIterable.sc:50) 
    at scala.collection.TraversableOnce.mkString(LinkedListIterable.sc:319) 
    at scala.collection.TraversableOnce.mkString$(LinkedListIterable.sc:318) 
    at #worksheet#.Node.mkString(LinkedListIterable.sc:6) 
    at scala.collection.TraversableLike.toString(LinkedListIterable.sc:596) 
    at scala.collection.TraversableLike.toString$(LinkedListIterable.sc:596) 
    at #worksheet#.Node.toString(LinkedListIterable.sc:6) 
    at java.lang.String.valueOf(LinkedListIterable.sc:2990) 
    at scala.collection.mutable.StringBuilder.append(LinkedListIterable.sc:196) 
    at scala.collection.TraversableOnce.$anonfun$addString$1(LinkedListIterable.sc:355) 
    at scala.collection.Iterator.foreach(LinkedListIterable.sc:925) 
    at scala.collection.Iterator.foreach$(LinkedListIterable.sc:925) 
    at scala.collection.AbstractIterator.foreach(LinkedListIterable.sc:1413) 
    at scala.collection.IterableLike.foreach(LinkedListIterable.sc:67) 
    at scala.collection.IterableLike.foreach$(LinkedListIterable.sc:66) 
    at #worksheet#.Node.foreach(LinkedListIterable.sc:6) 
    at scala.collection.TraversableOnce.addString(LinkedListIterable.sc:353) 
    at scala.collection.TraversableOnce.addString$(LinkedListIterable.sc:349) 
    at #worksheet#.Node.addString(LinkedListIterable.sc:6) 
    at scala.collection.TraversableOnce.mkString(LinkedListIterable.sc:319) 
    at scala.collection.TraversableOnce.mkString$(LinkedListIterable.sc:318) 
    at #worksheet#.Node.mkString(LinkedListIterable.sc:6) 
    at scala.collection.TraversableLike.toString(LinkedListIterable.sc:596) 
    at scala.collection.TraversableLike.toString$(LinkedListIterable.sc:596) 
    at #worksheet#.Node.toString(LinkedListIterable.sc:6) 
    at java.lang.String.valueOf(LinkedListIterable.sc:2990) 
    at scala.collection.mutable.StringBuilder.append(LinkedListIterable.sc:196) 
    at scala.collection.TraversableOnce.$anonfun$addString$1(LinkedListIterable.sc:355) 
    at scala.collection.Iterator.foreach(LinkedListIterable.sc:925) 
Output exceeds cutoff limit. 

更新:

的问题是通过在容器和一些值不是提及@Dima,迭代器,迭代容器本身。一旦明确,我修改了代码,如下所示运行正常。

trait LinkedList extends Iterable[Int]{ 
    val nodeValue: Int 
    val tailList: LinkedList 
    override def toString(): String = this.mkString(" -> ") 
} 

class Node(val nodeValue: Int, val tailList: LinkedList) extends LinkedList { 

    override def iterator: Iterator[Int] = Iterator 
    .iterate(this: LinkedList)(_.tailList) 
    .takeWhile(_ != Nil) 
    .map(_.nodeValue) 
} 

object Nil extends LinkedList { 
    lazy val nodeValue= throw new IllegalAccessException("head of Nil") 
    lazy val tailList = throw new IllegalAccessException("tail of Nil") 

    override def iterator: Iterator[Int] = Iterator.empty 
} 

val singleLinkedList = new Node(1,Nil) 
val chainedLinkedList = new Node(2,singleLinkedList) 

//Printing this first Time 
chainedLinkedList.foreach(println) 

回答

3

好了,问题是,在容器中,而不是实际的集装箱节点正常Iterable.iterator迭代。

这里会发生什么事,就是当你在REPL键入new Node(1, Nil),它试图打印出结果,并呼吁Node.toString,这是在Iterable实现在整个容器进行迭代,并且所有值转换为字符串。

因此,它会调用您的iterator,获取next(它认为是)元素,并尝试将其转换为字符串。但是iterator返回的值不是存储在节点中的值,而是节点本身,所以当调用toString时,它仍然是相同的Iterable.toString,最后调用相同的iterator,它将返回相同的值节点,它会尝试转换为字符串...等无限递归。

+0

经验教训。第一行总结了一切。我更新它在Int上迭代,一切都很好。 –

相关问题