简而言之:AnIterator
确实有状态,而 anIterable
没有。
请参阅两者的 API 文档。
可迭代:
可迭代集合的基本特征。
这是所有 Scala 集合的基本特征,它定义了一个迭代器方法来逐个遍历集合的元素。[...] 这个 trait 通过使用迭代器遍历所有元素来实现 Iterable 的 foreach 方法。
迭代器:
迭代器是允许迭代一系列元素的数据结构。它们有一个 hasNext 方法来检查是否有下一个元素可用,还有一个 next 方法返回下一个元素并将其从迭代器中丢弃。
迭代器是可变的:对它的大多数操作都会改变它的状态。虽然它通常用于遍历集合的元素,但它也可以在没有任何集合支持的情况下使用(参见伴随对象的构造函数)。
Iterator
如果需要,您可以使用 an停止迭代并在以后继续。如果您尝试使用 a 执行此操作,Iterable
它将再次从头部开始:
scala> val iterable: Iterable[Int] = 1 to 4
iterable: Iterable[Int] = Range(1, 2, 3, 4)
scala> iterable.take(2)
res8: Iterable[Int] = Range(1, 2)
scala> iterable.take(2)
res9: Iterable[Int] = Range(1, 2)
scala> val iterator = iterable.iterator
iterator: Iterator[Int] = non-empty iterator
scala> if (iterator.hasNext) iterator.next
res23: AnyVal = 1
scala> if (iterator.hasNext) iterator.next
res24: AnyVal = 2
scala> if (iterator.hasNext) iterator.next
res25: AnyVal = 3
scala> if (iterator.hasNext) iterator.next
res26: AnyVal = 4
scala> if (iterator.hasNext) iterator.next
res27: AnyVal = ()
请注意,我没有使用take
on Iterator
。这样做的原因是它使用起来很棘手。hasNext
并且next
是唯一可以保证按预期工作的两种方法Iterator
。再次查看Scaladoc:
特别重要的是要注意,除非另有说明,否则在调用迭代器的方法后绝不应使用迭代器。两个最重要的例外也是唯一的抽象方法:next 和 hasNext。
这两种方法都可以被调用任意次数,而不必丢弃迭代器。请注意,即使 hasNext 也可能导致突变——例如从输入流迭代时,它将阻塞直到流关闭或某些输入可用。
考虑以下示例以进行安全和不安全的使用:
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
}