4

Iterator[T] 上的 Scala 文档说明如下

特别重要的是要注意,除非另有说明,否则在调用迭代器的方法后绝不应使用迭代器。两个最重要的例外也是唯一的抽象方法:nexthasNext.

他们还给出了安全和不安全使用的具体示例:

def f[A](it: Iterator[A]) = {
  if (it.hasNext) {            // Safe to reuse "it" after "hasNext"
    it.next                    // Safe to reuse "it" after "next"
    val remainder = it.drop(2) // it is *not* safe to use "it" again after this line!
    remainder.take(2)          // it is *not* safe to use "remainder" after this line!
  } else it
}

不幸的是,我在这里没有遵循不安全的想法。有人可以在这里为我阐明一下吗?

4

2 回答 2

5

这是一个具体的例子:

def eleventh[A](xs: Iterator[A]) = {
  xs.take(10).toList
  xs.next
}

我们可以试一试:

scala> eleventh((1 to 100).toList.toIterator)
res0: Int = 11

scala> eleventh((1 to 100).toStream.toIterator)
res1: Int = 11

scala> eleventh(Stream.from(1).toIterator)
res2: Int = 11

看起来不错。但是之后:

scala> eleventh((1 to 100).toIterator)
res3: Int = 1

Now(1 to 100).toIterator具有与 相同的类型(1 to 100).toList.toIterator,但两者在这里的行为非常不同——我们看到实现细节从 API 中泄露出来。这是一件非常糟糕的事情,并且是将纯函数组合take器(如迭代器)与固有的命令式和可变概念混合的直接结果。

于 2013-08-24T18:07:04.320 回答
4

val remainder = it.drop(2)可以这样实现:它创建一个新的包装迭代器,它保留对原始it运算符的引用并将其推进两次,以便下次调用remainder.next时获得第三个元素。但是如果你it.next在两者之间调用,remainder.next将返回第四个元素......

因此,您必须引用remainder并且it可能需要调用next并执行相同的副作用,这是实现不支持的。

于 2013-08-24T18:11:56.577 回答