Scala:Scala集合中的Traversable和Iterable特征有什么区别?


Answers:


121

简而言之,迭代器保持状态,可遍历不保持状态。

A Traversable有一个抽象方法:foreach。当您调用时foreach集合将依次保存传递给函数的所有元素。

另一方面,具有Iterablehas作为抽象方法iterator,它返回Iterator。你可以叫nextIterator你的选择的时间去下一个元素。在执行此操作之前,它必须跟踪它在集合中的位置以及下一步。


4
但是Iterableextends Traversable,所以我想你的意思Traversable是不是Iterable
罗宾·格林

4
@RobinGreen我的意思是遵守Traversable接口不需要保持状态,而遵守Iterator接口则需要保持状态。
Daniel C. Sobral

10
TraversableS中的Iterable不保留任何迭代状态。这是Iterator创建并返回Iterable,保持状态。
Graham Lea 2014年

1
值得一提的是,自2.13版起,Traversable已弃用。用Stefan Zeiger的话说:“ Traversable抽象在当前库中并未发挥作用,并且可能不会在新设计中浮出水面。我们想要做的一切都可以用Iterable表示。”
Igor Urisman '19

226

可以将其视为吹和吸之间的区别。

调用Traversables foreach或其派生方法后,它将一次将其值吹入函数中-因此它可以控制迭代。

通过Iteratorif返回Iterable,您可以从中吸取值,控制何时自己移至下一个。


49
人们用它来调用这个推动拉动,而不是,但我喜欢你的思想开放。
马丁

2
在我的下一次采访中被问到时,请永远不要忘记这一点
thestephenstanton

23

TL;博士 IterablesTraversables可以产生状态Iterators


首先,要知道Iterable是的子特性Traversable

第二,

  • Traversable需要实现该foreach方法,该方法将被其他所有方法使用。

  • Iterable需要实现该iterator方法,该方法将被其他所有方法使用。

例如,findfor 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减重写此实施和电话findIterator,一旦元素被发现,它只是停止迭代:

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它是更苛刻/更强大的特性,因为您可以轻松实现foreachusing iterator,但不能真正实现iteratorusing foreach


总之,Iterable提供了一种通过有状态的暂停,继续或停止迭代的方法Iterator。使用Traversable,它全有还是全无(流量控制没有例外)。

在大多数情况下,这并不重要,您将需要更通用的界面。但是,如果您需要对迭代进行更多的自定义控制,则需要一个Iterator,您可以从中进行检索Iterable


1

丹尼尔的回答听起来不错。让我看看是否可以用我自己的话说。

因此,Iterable可以为您提供一个迭代器,使您可以一次遍历元素(使用next()),并根据需要停止并继续。为此,迭代器需要为元素的位置保留一个内部“指针”。但是Traversable为您提供了一次遍历所有元素而无需停止的方法foreach。

像Range(1,10)这样的东西只需要2个整数作为Traversable状态即可。但是Range(1,10)作为Iterable可以为您提供一个迭代器,该迭代器需要使用3个整数作为状态,其中一个是索引。

考虑到Traversable还提供foldLeft,foldRight,因此它的foreach需要以已知的固定顺序遍历元素。因此,可以为Traversable实现一个迭代器。例如def iterator = toList.iterator

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.