我认为问题可能在于Record.key 只是返回某个变量的当前值,该变量在迭代器被消耗时发生了变异
(而不是让记录在构建时实际捕获关键值)。
一个例子可能会让它更清楚。
首先,让我们使用 scala REPL 编写一些没有出现问题的测试代码:
case class Record( key: Int )
def getRecordIterator: Iterator[Record] = {
var currentKey: Int = 0
(1 to 10).iterator.map{ i =>
currentKey += 1
new Record( currentKey )
}
}
那么我们可以尝试不使用grouped进行迭代:
for ((record, i) <- getRecordIterator.zipWithIndex) {
println(i + "|" + record)
}
这给了我们(如预期的那样)
0|Record(1)
1|Record(2)
2|Record(3)
3|Record(4)
4|Record(5)
5|Record(6)
6|Record(7)
7|Record(8)
8|Record(9)
9|Record(10)
然后使用grouped:
for (group <- getRecordIterator.zipWithIndex.grouped(3)) {
for ((record, i) <- group) {
println(i + "|" + record)
}
println("---")
}
这给出了:
0|Record(1)
1|Record(2)
2|Record(3)
---
3|Record(4)
4|Record(5)
5|Record(6)
---
6|Record(7)
7|Record(8)
8|Record(9)
---
9|Record(10)
---
到目前为止,一切都很好。
现在我们稍微改变一下Record的定义:
trait Record {
def key: Int
override def toString = "Record(" + key + ")"
}
def getRecordIterator: Iterator[Record] = {
var currentKey: Int = 0
(1 to 10).iterator.map{ i =>
currentKey += 1
new Record{ def key = currentKey }
}
}
有了这个改变,我们在不使用grouped 时仍然得到相同的结果,但是当我们使用group 时得到的结果如下:
0|Record(3)
1|Record(3)
2|Record(3)
---
3|Record(6)
4|Record(6)
5|Record(6)
---
6|Record(9)
7|Record(9)
8|Record(9)
---
9|Record(10)
---
问题的根源在于,仅仅在我们的迭代器上调用next 就改变了Record.get 返回的值。
这个问题可以更简单地说明:
val it = getRecordIterator
val r1 = it.next
println(r1) // prints "Record(1)" as expected
val r2 = it.next
println(r2) // prints "Record(2)" as expected
println(r1) // this now prints "Record(2)", not "Record(1)" anymore!