2014-10-06 80 views
0

我试图建立一个懒惰的迭代器,从阻塞队列拉,并遇到一个奇怪的问题,其中next()似乎被调用超过预期的时间。由于我的队列被阻塞,这会导致我的应用程序在某些情况下卡住。scala - 懒惰的迭代器调用下次太多次?

有些简化的示例代码:

"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

正如@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()以上的最少次数。