我查看了这个问题,但仍然不明白Iterable和Traversable特质之间的区别。有人能解释一下吗?
将其视为吹和吸之间的区别。
当您调用Traversable
的foreach
或其衍生方法时,它会逐个将其值传递到您的函数中-因此它控制着迭代。
但通过由Iterable
返回的Iterator
,您可以从中提取值,并自行控制何时移动到下一个值。
简单来说,迭代器保留状态,可遍历对象则不保留。
Traversable
(可遍历)有一个抽象方法:foreach
。当你调用foreach
方法时,这个集合会依次将它所保存的所有元素传递给传入的函数。
另一方面,Iterable
(可迭代)则有一个抽象方法iterator
,返回一个Iterator
(迭代器)。你可以在任意时间调用Iterator
的next
方法,以获取下一个元素。在你调用next
方法之前,迭代器必须跟踪它在集合中的位置及后续还有哪些元素。
Iterable
扩展自 Traversable
,所以我猜你指的是那些不是 Iterable
的 Traversable
。 - Robin GreenTraversable
接口不需要保持状态,而遵循 Iterator
接口则需要。 - Daniel C. SobralIterable
接口的可遍历对象并不保留任何遍历状态,而是由实现Iterable
接口的对象创建并返回一个Iterator
对象来保存状态。 - Graham Leatl;dr Iterables
是能够产生有状态的 Iterators
的 Traversables
首先要知道,Iterable
是 Traversable
的子特质。
其次,
Traversable
需要实现 foreach
方法,它被其他方法使用。
Iterable
需要实现 iterator
方法,它被其他方法使用。
例如,Traversable
的 find
实现使用 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
的 subtract
方法会覆盖这个实现,并在 Iterator
上调用 find
方法,一旦找到元素就停止迭代:
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
是更具要求/强大的特性,因为您可以轻松地使用iterator
实现foreach
,但您无法真正使用foreach
实现iterator
。
总之,Iterable
通过有状态的Iterator
提供了一种暂停、恢复或停止迭代的方式。对于Traversable
,它要么全部执行(除了流程控制异常),要么不执行。
大多数情况下,这并不重要,您将需要更通用的接口。但如果您需要更多定制化的迭代控制,则需要一个Iterator
,您可以从一个Iterable
中检索到它。
Daniel的回答听起来不错。让我试着用自己的话来解释一下。
所以,一个Iterable可以给你一个迭代器,让你逐个遍历元素(使用next()),并随时停止和继续。为了做到这一点,迭代器需要保持对元素位置的内部“指针”。但是Traversable通过提供foreach方法来一次性遍历所有元素,而不需要停止。
像Range(1,10)这样的东西只需要作为Traversable拥有2个整数状态。但是,Range(1,10)作为Iterable会给你一个迭代器,需要使用3个整数作为状态,其中之一是索引。
考虑到Traversable还提供了foldLeft、foldRight,它的foreach需要按照已知和固定的顺序遍历元素。因此,可以为Traversable实现一个迭代器。例如: def iterator = toList.iterator
Traversable
了(它仍然作为Iterable
的弃用别名保留到2.14)。 - Xavier Guihot