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

时间:2011-09-15 02:56:05

标签: scala scala-collections

我看过this question,但仍然不理解Iterable和Traversable特征之间的区别。有人可以解释一下吗?

4 个答案:

答案 0 :(得分:217)

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

当您调用Traversable s foreach或其派生方法时,它会一次将其值放入您的函数中 - 因此它可以控制迭代。

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

答案 1 :(得分:112)

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

Traversable有一个抽象方法:foreach。当您致电foreach时,集合会将传递的所有元素一个接一个地传递给传递函数。

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

答案 2 :(得分:20)

tl; dr Iterables Traversables可以产生有状态的Iterators

首先,要知道IterableTraversable的子网格。

第二,

  • 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