2014-10-06 77 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()以上的最少次數。