我看过this question,但仍然不理解Iterable和Traversable特征之间的区别。有人可以解释一下吗?
答案 0 :(得分:217)
将其视为吹吮和吸吮之间的区别。
当您调用Traversable
s foreach
或其派生方法时,它会一次将其值放入您的函数中 - 因此它可以控制迭代。
使用Iterator
返回的Iterable
,你会从中取出值,控制何时自己移动到下一个。
答案 1 :(得分:112)
简而言之,迭代器保持状态,遍历不会。
Traversable
有一个抽象方法:foreach
。当您致电foreach
时,集合会将传递的所有元素一个接一个地传递给传递函数。
另一方面,Iterable
具有抽象方法iterator
,它返回Iterator
。您可以在next
上致电Iterator
,以便在您选择时获取下一个元素。在你做之前,它必须跟踪它在集合中的位置,以及接下来的内容。
答案 2 :(得分:20)
tl; dr Iterables
Traversables
可以产生有状态的Iterators
首先,要知道Iterable
是Traversable
的子网格。
第二,
Traversable
需要实施foreach
方法,其他所有方法都使用该方法。
Iterable
需要实施iterator
方法,其他所有方法都使用该方法。
例如,find
Traversable
的实现使用foreach
(通过for comprehension)并抛出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
迭代抛出异常会很好,但这是仅使用foreach
时部分迭代的唯一方法。
从一个角度来看,Iterable
是更苛刻/更强大的特性,因为您可以使用foreach
轻松实现iterator
,但您无法真正实现iterator
foreach
。
总之,Iterable
提供了一种通过有状态Iterator
暂停,恢复或停止迭代的方法。使用Traversable
,它是全部或全部(没有流控制的例外)。
大多数时候没关系,你会想要更通用的界面。但是,如果您需要对迭代进行更多自定义控制,则需要Iterator
,您可以从Iterable
检索。
答案 3 :(得分:0)
丹尼尔的答案听起来不错。让我看看是否可以用我自己的话来表达。
因此,一个Iterable可以为您提供一个迭代器,使您可以一次遍历元素(使用next()),并根据需要停下来。为此,迭代器需要为元素的位置保留一个内部“指针”。但是Traversable为您提供了一次foreach的方法,可以不间断地遍历所有元素。
像Range(1,10)这样的东西只需要2个整数作为Traversable状态即可。但是Range(1,10)作为Iterable可以为您提供一个迭代器,该迭代器需要使用3个整数作为状态,其中一个是索引。
考虑到Traversable还提供foldLeft,foldRight,它的foreach需要以已知的固定顺序遍历元素。因此,可以为Traversable实现迭代器。例如。 def iterator = toList.iterator