【发布时间】:2011-09-15 02:56:05
【问题描述】:
我查看了this question,但仍然不明白 Iterable 和 Traversable 特征之间的区别。谁能解释一下?
【问题讨论】:
-
Scala 2.13 中不再有
Traversable(在 2.14 之前,它仍作为Iterable的已弃用别名保留)
我查看了this question,但仍然不明白 Iterable 和 Traversable 特征之间的区别。谁能解释一下?
【问题讨论】:
Traversable(在 2.14 之前,它仍作为 Iterable 的已弃用别名保留)
把它想象成吹和吸的区别。
当您调用 Traversables foreach 或其派生方法时,它将一次将其值放入您的函数中 - 因此它可以控制迭代。
虽然Iterable 返回了Iterator,但您可以从中吸取价值,自己控制何时移至下一个。
【讨论】:
简单地说,迭代器保持状态,可遍历不保持。
Traversable 有一个抽象方法:foreach。当您调用foreach 时,集合 会将其保留的所有元素一个接一个地提供给传递的函数。
另一方面,Iterable 具有抽象方法iterator,它返回Iterator。您可以在Iterator 上致电next,以便在您选择时获取下一个元素。在您这样做之前,它必须跟踪它在集合中的位置,以及下一步是什么。
【讨论】:
Iterable 扩展了Traversable,所以我猜你的意思是Traversables 不是Iterables。
Traversable接口不需要保持状态,而遵守Iterator接口需要。
Traversables 是Iterable 不保持任何迭代状态。保持状态的是由Iterable 创建和返回的Iterator。
tl;dr 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 减法覆盖此实现并在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 中检索它。
【讨论】:
丹尼尔的回答听起来不错。让我看看能不能用我自己的话来说。
因此,Iterable 可以为您提供一个迭代器,让您一次遍历一个元素(使用 next()),并随心所欲地停止和移动。为此,迭代器需要保持一个指向元素位置的内部“指针”。但是 Traversable 为您提供了 foreach 方法,可以一次遍历所有元素而不会停止。
像 Range(1, 10) 这样的东西只需要 2 个整数作为 Traversable 的状态。但是 Range(1, 10) 作为 Iterable 为您提供了一个迭代器,它需要为状态使用 3 个整数,其中一个是索引。
考虑到 Traversable 还提供 foldLeft、foldRight,它的 foreach 需要以已知且固定的顺序遍历元素。因此,可以为 Traversable 实现迭代器。例如。 def iterator = toList.iterator
【讨论】: