我想添加一条关于流与迭代器的评论。流和迭代器都可用于实现长的、非严格的、可能无限的集合,在需要时才计算值。
但是,这样做时会出现“过早执行”的一个棘手问题,可以使用迭代器而不是流来避免,并且在此过程中指出了两者之间的重要语义差异。这也许最清楚地说明如下:
def runiter(start: Int) {
// Create a stream that returns successive integers on demand, e.g. 3, 4, 5, ....
val iter = {
def loop(v: Int): Stream[Int] = { println("I computed a value", v); v} #:: loop(v+1)
loop(start)
}
// Now, sometime later, we retrieve the values ....
println("about to loop")
for (x <- iter) {
if (x < 10) println("saw value", x) else return
}
}
此代码创建一个从给定值开始并返回连续整数的无限流。它用作更复杂代码的替身,例如,可能会打开 Internet 连接并根据需要从连接中返回值。
结果:
scala> runiter(3)
(I computed a value,3)
about to loop
(saw value,3)
(I computed a value,4)
(saw value,4)
(I computed a value,5)
(saw value,5)
(I computed a value,6)
(saw value,6)
(I computed a value,7)
(saw value,7)
(I computed a value,8)
(saw value,8)
(I computed a value,9)
(saw value,9)
(I computed a value,10)
仔细注意计算第一个值所需的执行是如何在实际使用流的值的位置之前发生的。例如,如果此初始执行涉及打开文件或 Internet 连接,并且在创建流之后和使用任何值之前有很长的延迟,这可能会非常有问题 - 您最终会得到一个打开的文件描述符更糟糕的是,您的互联网连接可能会超时,导致整个过程失败。
使用初始空流修复它的简单尝试不起作用:
def runiter(start: Int) {
// Create a stream that returns successive integers on demand, e.g. 3, 4, 5, ....
val iter = {
def loop(v: Int): Stream[Int] = { println("I computed a value", v); v} #:: loop(v+1)
Stream[Int]() ++ loop(start)
}
// Now, sometime later, we retrieve the values ....
println("about to loop")
for (x <- iter) {
if (x < 10) println("saw value", x) else return
}
}
结果(和之前一样):
scala> runiter(3)
(I computed a value,3)
about to loop
(saw value,3)
(I computed a value,4)
(saw value,4)
(I computed a value,5)
(saw value,5)
(I computed a value,6)
(saw value,6)
(I computed a value,7)
(saw value,7)
(I computed a value,8)
(saw value,8)
(I computed a value,9)
(saw value,9)
(I computed a value,10)
但是,您可以通过将流更改为具有初始空迭代器的迭代器来解决此问题,即使这种情况远非显而易见:
def runiter(start: Int) {
// Create an iterator that returns successive integers on demand, e.g. 3, 4, 5, ....
val iter = {
def loop(v: Int): Iterator[Int] = { println("I computed a value", v); Iterator(v)} ++ loop(v+1)
Iterator[Int]() ++ loop(start)
}
// Now, sometime later, we retrieve the values ....
println("about to loop")
for (x <- iter) {
if (x < 10) println("saw value", x) else return
}
}
结果:
scala> runiter(3)
about to loop
(I computed a value,3)
(saw value,3)
(I computed a value,4)
(saw value,4)
(I computed a value,5)
(saw value,5)
(I computed a value,6)
(saw value,6)
(I computed a value,7)
(saw value,7)
(I computed a value,8)
(saw value,8)
(I computed a value,9)
(saw value,9)
(I computed a value,10)
请注意,如果您不添加初始的空迭代器,您将遇到与流相同的过早执行问题。