Iterable和Iterator之间有什么关系?

问题描述:

scala中 Iterator Iterable 之间的区别是什么?

What is the difference between Iterator and Iterable in scala?

我认为 Iterable 代表一个我可以迭代的集合, Iterator 是一个指针到可迭代集合中的一个项目。

I thought that Iterable represents a set that I can iterate through, and Iterator is a "pointer" to one of the items in the iterable set.

然而, Iterator 具有 forEach map foldLeft 。它可以通过 toIterable 转换为 Iterable 。例如, scala.io.Source.getLines 返回 Iterator ,而不是 Iterable

However, Iterator has functions like forEach, map, foldLeft. It can be converted to Iterable via toIterable. And, for example, scala.io.Source.getLines returns Iterator, not Iterable.

但是我无法在 Iterator上执行 groupBy 我可以在 Iterable 上做。

那么,这两者之间的关系是什么, Iterator Iterable

So, what's the relation between those two, Iterator and Iterable?

简而言之:迭代器确实有状态,而 Iterable 则没有。

In short: An Iterator does have state, whereas an Iterable does not.

请参阅两者的API文档。

See the API docs for both.

Iterable


一个基本特征可迭代集合。

A base trait for iterable collections.

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

This is a base trait for all Scala collections that define an iterator method to step through one-by-one the collection's elements. [...] This trait implements Iterable's foreach method by stepping through all elements using iterator.

迭代器


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

Iterators are data structures that allow to iterate over a sequence of elements. They have a hasNext method for checking if there is a next element available, and a next method which returns the next element and discards it from the iterator.

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

An iterator is mutable: most operations on it change its state. While it is often used to iterate through the elements of a collection, it can also be used without being backed by any collection (see constructors on the companion object).

使用 Iterator ,您可以停止迭代并在以后继续(如果需要)。如果您尝试使用 Iterable 执行此操作,它将从头开始:

With an Iterator you can stop an iteration and continue it later if you want. If you try to do this with an Iterable it will begin from the head again:

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 = ()

注意,我没有在 Iterator 上使用。原因是它使用起来很棘手。 hasNext next 是唯一保证在 Iterator 。再次查看 Scaladoc

Note, that I didn't use take on Iterator. The reason for this is that it is tricky to use. hasNext and next are the only two methods that are guaranteed to work as expected on Iterator. See the Scaladoc again:


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

It is of particular importance to note that, unless stated otherwise, one should never use an iterator after calling a method on it. The two most important exceptions are also the sole abstract methods: next and hasNext.

这两种方法都可以被调用任意次多次不得不
丢弃迭代器。请注意,即使hasNext可能会导致变异 -
,例如从输入流进行迭代时,它将阻塞直到
流关闭或某些输入变为可用。

Both these methods can be called any number of times without having to discard the iterator. Note that even hasNext may cause mutation -- such as when iterating from an input stream, where it will block until the stream is closed or some input becomes available.

考虑这个安全和不安全使用的例子:

Consider this example for safe and unsafe use:

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
}