如何寫一個正確的iterator

咱們知道, iterator 是一個可變對象, 換句話來講, 它的next方法是有反作用的。
 對於那些由容器產生的iterator來講, hasNext通常都是沒有反作用的。可是, 某些時候, hasNext也是可能有反作用的。舉個例子來講, 若是咱們要基於BufferedReader來寫一個能夠迭代行的迭代器, 咱們就要在hashNext裏面嘗試讀取新的一行, 因而, 反作用就產生了。 

當咱們的hasNext方法是有反作用的時候, 就要特別當心了。由於用戶有可能會連續屢次調用hasNext這個方法!

同時,咱們還要考慮一個問題。 通常狀況下, 咱們理想的迭代器使用方法是這樣的

if (iter.hasNext) { val v = iter.next; 使用v來作一些事情 } else {退出迭代過程}
if (iter.hasNext) { val v = iter.next; 使用v來作一些事情 } else {退出迭代過程}
if (iter.hasNext) { val v = iter.next; 使用v來作一些事情 } else {退出迭代過程}

...... java


也就是說, 咱們的迭代器的正確性依賴於 hasNext, next, hasNext, next....這個「合理的」調用序列
可是, 事實上, 用戶其實並不必定會按照這種正確的調用順序來使用咱們的迭代器。

爲了實現一個可讓用戶隨意安排調用序列, 咱們要讓迭代器知足兩個性質:
1。任什麼時候候, 任意兩次連續的hasNext方法, 老是等價於一次hasNext
2。任什麼時候候, 任意兩次連續的next方法, 都等價於在這兩個next方法中間插入一個hasNext方法

所謂的「a等價於b」, 就是說, 不管是經過途徑a仍是途徑b, iterator最後的內部狀態 都是同樣的。

 只要同時知足這兩個性質, 就能夠放心地把iterator的正確性 設計成 依賴於 hasNext, next, hasNext, next....這個「合理的」調用序列 。 curl


能夠發現, 對於基於容器(List,Map,Set等等)的iterator來講, 這兩個性質是「自然地, 直接地, 簡單地」就知足的。其緣由在於:若是hasNext方法是無反作用的,那麼上面的兩個性質必定會知足this

可是當咱們要寫一些並非基於容器的迭代器的時候, 這時候hasNext方法有可能會有反作用, 咱們就要注意檢查是否知足上面兩個條件了。 url


總結起來: scala

看成爲iterator的編寫者的時候: 咱們要儘可能讓hasNext沒有反作用,若是實在不行,就要注意驗證是否是可以知足上面的兩個性質.  設計

看成爲iterator的使用者的時候: 咱們要假定hasNext是有反作用的, 因此要嚴格按照hasNext, next ... 這個調用序列來使用別人寫的iterator code


最後,給出一個例子, 寫一個能夠迭代行的迭代器: 對象


import java.io._ def toReader(fp: String, enc: String): Reader = new InputStreamReader(new FileInputStream(new File(fp)), enc) def iLines(reader: Reader): Iterator[String] = { val br = new BufferedReader(reader) var curline = "" var checked = false var checkedRes = false new Iterator[String] { def hasNext: Boolean = { if (checked) return checkedRes checked = true curline = br.readLine() checkedRes = if (curline != null) true else false return checkedRes } def next: String = { if (!checked) this.hasNext checked = false return curline } } } 
相關文章
相關標籤/搜索