我正在尝试构建一个从阻塞队列中提取的惰性迭代器,并且遇到了一个奇怪的问题,next()
似乎被调用的次数多于预期。因为我的队列阻塞,这导致我的应用程序在某些情况下陷入困境。
一些简化的示例代码:
"infinite iterators" should {
def mkIter = new Iterable[Int] {
var i = 0
override def iterator: Iterator[Int] = {
new Iterator[Int] {
override def hasNext: Boolean = true
override def next(): Int = {
i = i + 1
i
}
}
}
override def toString(): String = "lazy"
}
"return subsets - not lazy" in {
val x = mkIter
x.take(2).toList must equal(List(1, 2))
x.take(2).toList must equal(List(3, 4))
}
"return subsets - lazy" in {
val x = mkIter
x.view.take(2).toList must equal(List(1, 2))
x.view.take(2).toList must equal(List(3, 4))
}
}
在上面的示例中,延迟测试失败,因为第二次调用take(2)
会返回List(4, 5)
。
鉴于我在Scala 2.10和2.11中都看到了这种行为,我怀疑错误是我的,但我不确定我错过了什么。
答案 0 :(得分:2)
使无效的迭代器。请参阅http://www.scala-lang.org/api/2.10.3/index.html#scala.collection.Iterator
顶部的代码示例答案 1 :(得分:0)
正如@dlwh所解释的那样,Scala被明确记录为在调用take(Int)
之后不允许重用迭代器。也就是说,实现我的核心用例的一种方法是每次我想从迭代器中获取另一个元素时创建一个新的流。
在原始问题中添加我的示例:
"return subsets - streams" in {
val x = mkIter
x.toStream.take(2).toList must equal(List(1, 2))
x.toStream.take(2).toList must equal(List(3, 4))
}
请注意,toStream
具有在迭代器上调用next()
的副作用,因此,只有当您知道将从流中取出至少一个项目时,这才是安全的。优势流超过懒惰的视图是它不会调用next()
超过所需的最少次数。