【问题标题】:Scala: What is the difference between Traversable and Iterable traits in Scala collections?Scala:Scala 集合中的 Traversable 和 Iterable 特征有什么区别?
【发布时间】:2011-09-15 02:56:05
【问题描述】:

我查看了this question,但仍然不明白 Iterable 和 Traversable 特征之间的区别。谁能解释一下?

【问题讨论】:

  • Scala 2.13 中不再有 Traversable(在 2.14 之前,它仍作为 Iterable 的已弃用别名保留)

标签: scala scala-collections


【解决方案1】:

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

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

虽然Iterable 返回了Iterator,但您可以从中吸取价值,自己控制何时移至下一个。

【讨论】:

  • 人们习惯称之为,而不是,但我喜欢你的开放态度。
  • 在我的下一次采访中被问到时永远不会忘记这一点
【解决方案2】:

简单地说,迭代器保持状态,可遍历不保持。

Traversable 有一个抽象方法:foreach。当您调用foreach 时,集合 会将其保留的所有元素一个接一个地提供给传递的函数。

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

【讨论】:

  • 但是Iterable 扩展了Traversable,所以我猜你的意思是Traversables 不是Iterables。
  • @RobinGreen 我的意思是遵守Traversable接口不需要保持状态,而遵守Iterator接口需要。
  • Traversables 是Iterable 不保持任何迭代状态。保持状态的是由Iterable 创建和返回的Iterator
  • 值得注意的是,从 2.13 开始,trait Traversable 已被弃用。引用 Stefan Zeiger 的话,“Traversable 抽象在当前库中没有发挥作用,并且很可能不会在新设计中重新出现。我们想做的一切都可以用 Iterable 来表达。”
【解决方案3】:

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


首先,要知道IterableTraversable 的子特征。

第二,

  • 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 中检索它。

【讨论】:

    【解决方案4】:

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

    因此,Iterable 可以为您提供一个迭代器,让您一次遍历一个元素(使用 next()),并随心所欲地停止和移动。为此,迭代器需要保持一个指向元素位置的内部“指针”。但是 Traversable 为您提供了 foreach 方法,可以一次遍历所有元素而不会停止。

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

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

    【讨论】:

      猜你喜欢
      • 2016-04-05
      • 2011-06-03
      • 1970-01-01
      • 1970-01-01
      • 2018-05-08
      • 1970-01-01
      • 2017-01-01
      • 1970-01-01
      • 2020-12-14
      相关资源
      最近更新 更多