it-swarm.cn

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

我看了 这个问题 但仍然不理解Iterable和Traversable特征之间的区别。谁能解释一下?

90
Rahul

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

Traversable有一个抽象方法:foreach。当你调用foreach时, 集合 将一个接一个地传递它保留的所有元素。

另一方面,Iterable具有抽象方法iterator,它返回Iterator。您可以在next上调用Iterator以在您选择时获取下一个元素。在你做之前,它必须跟踪它在集合中的位置,以及下一步。

112
Daniel C. Sobral

把它想象成吹和吸吮之间的区别。

当你调用一个Traversables foreach或它的派生方法时,它会一次一个地将它的值放入你的函数中 - 所以它可以控制迭代。

使用Iterator返回的Iterable,你可以从中取出值,控制何时自己移动到下一个值。

217
Duncan McGregor

tl; dr IterablesTraversables,可以生成有状态的Iterators


首先,要知道IterableTraversable的子程序。

第二,

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

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

例如,findTraversable的实现使用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 subtract会覆盖此实现,并在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中检索它。

20
Paul Draper