Iterable和Iterator之间有什么关系?

时间:2012-07-02 22:56:59

标签: scala iterator

scala中的IteratorIterable之间有什么区别?

我认为Iterable表示我可以迭代的集合,Iterator是可迭代集合中某个项目的“指针”。

但是,Iterator具有forEachmapfoldLeft等功能。它可以通过Iterable转换为toIterable。例如,scala.io.Source.getLines返回Iterator,而不是Iterable

但我无法在groupBy IteratorIterable,我可以在Iterator上执行此操作。

那么,这两者之间的关系是什么,Iterable和{{1}}?

2 个答案:

答案 0 :(得分:62)

简而言之:Iterator确实有州,而Iterable则没有。

请参阅两者的API文档。

Iterable

  

可迭代集合的基本特征。

     

这是定义迭代器的所有Scala集合的基本特征   逐步逐步收集集合元素的方法。   [...]这个特性通过步进实现了Iterable的foreach方法   通过使用迭代器的所有元素。

Iterator

  

迭代器是允许迭代序列的数据结构   元素。他们有一个hasNext方法来检查是否有下一个   元素可用,以及返回下一个元素的下一个方法   并将其从迭代器中丢弃。

     

迭代器是可变的:它上面的大多数操作都会改变它的状态。而   它通常用于迭代集合的元素   也可以在没有任何集合支持的情况下使用(参见   伴侣对象上的构造函数。)

使用Iterator,您可以停止迭代,如果需要,可以稍后继续。如果您尝试使用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上使用Iterator。原因是它使用起来很棘手。 hasNextnext是唯一可以保证在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
}

答案 1 :(得分:5)

Martin Odersky和Lex Spoon的另一个解释:

  

foreach方法之间有一个重要的区别   可遍历集合上的迭代器和相同方法:调用时   对于迭代器,foreach会在迭代器结束时离开迭代器   完成。因此,在同一个迭代器上再次调用next将失败   NoSuchElementException异常。相比之下,当收集一个集合时,   foreach使集合中元素的数量保持不变   (除非传递的函数添加删除元素,但这是   气馁,因为它可能导致令人惊讶的结果)。

来源:http://www.scala-lang.org/docu/files/collections-api/collections_43.html

另请注意(感谢Wei-Ching Lin提供此提示)Iterator扩展了TraversableOnce特征,Iterable没有。