Answers:
简而言之,迭代器保持状态,可遍历不保持状态。
A Traversable
有一个抽象方法:foreach
。当您调用时foreach
,集合将依次保存传递给函数的所有元素。
另一方面,具有Iterable
has作为抽象方法iterator
,它返回Iterator
。你可以叫next
上Iterator
你的选择的时间去下一个元素。在执行此操作之前,它必须跟踪它在集合中的位置以及下一步。
Iterable
extends Traversable
,所以我想你的意思Traversable
是不是Iterable
。
Traversable
接口不需要保持状态,而遵守Iterator
接口则需要保持状态。
Traversable
S中的Iterable
不保留任何迭代状态。这是Iterator
创建并返回Iterable
,保持状态。
可以将其视为吹和吸之间的区别。
调用Traversable
s foreach
或其派生方法后,它将一次将其值吹入函数中-因此它可以控制迭代。
通过Iterator
if返回Iterable
,您可以从中吸取值,控制何时自己移至下一个。
TL;博士 Iterables
是Traversables
可以产生状态Iterators
首先,要知道Iterable
是的子特性Traversable
。
第二,
Traversable
需要实现该foreach
方法,该方法将被其他所有方法使用。
Iterable
需要实现该iterator
方法,该方法将被其他所有方法使用。
例如,find
for Traversable
用途的实现foreach
(通过for理解)并BreakControl
在找到令人满意的元素后抛出异常以暂停迭代。
trait TravserableLike {
def find(p: A => Boolean): Option[A] = {
var result: Option[A] = None
breakable {
for (x <- this)
if (p(x)) { result = Some(x); break }
}
result
}
}
相比之下,Iterable
减重写此实施和电话find
上Iterator
,一旦元素被发现,它只是停止迭代:
trait Iterable {
override /*TraversableLike*/ def find(p: A => Boolean): Option[A] =
iterator.find(p)
}
trait Iterator {
def find(p: A => Boolean): Option[A] = {
var res: Option[A] = None
while (res.isEmpty && hasNext) {
val e = next()
if (p(e)) res = Some(e)
}
res
}
}
最好不要在Traversable
迭代中抛出异常,但这是使用just进行部分迭代的唯一方法foreach
。
从一个角度看,Iterable
它是更苛刻/更强大的特性,因为您可以轻松实现foreach
using iterator
,但不能真正实现iterator
using foreach
。
总之,Iterable
提供了一种通过有状态的暂停,继续或停止迭代的方法Iterator
。使用Traversable
,它全有还是全无(流量控制没有例外)。
在大多数情况下,这并不重要,您将需要更通用的界面。但是,如果您需要对迭代进行更多的自定义控制,则需要一个Iterator
,您可以从中进行检索Iterable
。
丹尼尔的回答听起来不错。让我看看是否可以用我自己的话说。
因此,Iterable可以为您提供一个迭代器,使您可以一次遍历元素(使用next()),并根据需要停止并继续。为此,迭代器需要为元素的位置保留一个内部“指针”。但是Traversable为您提供了一次遍历所有元素而无需停止的方法foreach。
像Range(1,10)这样的东西只需要2个整数作为Traversable状态即可。但是Range(1,10)作为Iterable可以为您提供一个迭代器,该迭代器需要使用3个整数作为状态,其中一个是索引。
考虑到Traversable还提供foldLeft,foldRight,因此它的foreach需要以已知的固定顺序遍历元素。因此,可以为Traversable实现一个迭代器。例如def iterator = toList.iterator
Traversable
了(它一直保留为2.14之前已弃用的别名)Iterable