Scala Iterator ++打击堆栈

时间:2017-02-06 01:41:20

标签: scala iterator

我最近注意到这个由于lazy init导致Scala Iterator ++中出现StackOverFlowError的错误。这是出现错误的代码。

var lines = Source.fromFile("file").getLines()
var line = lines.next()
lines = Array(line).toIterator ++ lines
lines.foreach { println(_) }
System.exit(0)

我得到的是

Exception in thread "main" java.lang.StackOverflowError
at scala.collection.Iterator$JoinIterator.hasNext(Iterator.scala:219)
at scala.collection.Iterator$JoinIterator.hasNext(Iterator.scala:219)
at scala.collection.Iterator$JoinIterator.hasNext(Iterator.scala:219)
at scala.collection.Iterator$JoinIterator.hasNext(Iterator.scala:219)
...

它应该由scala源中的这一行引起(scala.collection.Iterator.scala:208)

lazy val rhs: Iterator[A] = that.toIterator

由于rhs是一个惰性初始值,当使用迭代器时,名称“lines”指的是已经改变,并引起循环引用,这会导致错误。

我注意到this post在2013年谈到了这个问题。但是它似乎还没有完全修复。我正在从Maven Repo运行Scala 2.11.8。

我的问题:我可以重命名迭代器,例如“lines2”以避免这个bug,但这是解决问题的唯一方法吗?我觉得使用“线条”这个名字更自然,如果可能的话也不想放弃它。

2 个答案:

答案 0 :(得分:2)

如果您想使用相同的Iterator重新加载var,这似乎有效。 [经测试2.11.7和2.12.1]

scala> var lines = io.Source.fromFile("file.txt").getLines()
lines: Iterator[String] = non-empty iterator

scala> var line = lines.next()
line: String = this,that,other,than

scala> lines = Iterator(line +: lines.toSeq:_*)
lines: Iterator[String] = non-empty iterator

scala> lines.foreach(println)
this,that,other,than
here,there,every,where

但是使用BufferedIterator可能更有意义,可以在其上调用head来查看下一个元素而不使用它。

<强>解释

lines.toSeq&lt; - 将Iterator[String]转换为Seq[String](REPL会将此显示为Stream,但这是因为REPL必须编译并代表每个输入线分开。)

line +: lines.toSeq&lt; - 创建一个新的Seq[String]line作为第一个元素(即前置)

(line +: lines.toSeq:_*)&lt; - 将单个Seq[T]转换为可以传递给Iterator.apply()方法的参数列表。 @ som-snytt巧妙地指出,这可以简化为(line +: lines.toSeq).iterator

BufferedIterator示例

scala> var lines = io.Source.fromFile("file.txt").getLines.buffered
lines: scala.collection.BufferedIterator[String] = non-empty iterator
                        ^^^^^^^^^^^^^^^^^^^^^^^^ <-- note the type

scala> lines.head
res5: String = this,that,other,than

scala> lines foreach println
this,that,other,than
here,there,every,where

答案 1 :(得分:0)

简单捕获:

scala> var lines = Iterator.continually("x")
lines: Iterator[String] = non-empty iterator

scala> lines = { val z = lines ; Iterator.single("y") ++ z }
lines: Iterator[String] = non-empty iterator

scala> lines.next
res0: String = y

scala> lines.next
res1: String = x
相关问题