我认为问题可能是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!