【问题标题】:Is using Scala's Iterator ++ (concat) recursively stack-safe?使用 Scala 的 Iterator ++ (concat) 递归堆栈安全吗?
【发布时间】:2017-06-23 18:30:28
【问题描述】:

假设您使用的 API 允许您在页面中滚动浏览结果集。每个页面都为后续页面返回一个 ID。

您可以使用 Scala Iterator 及其惰性 concat (++) 运算符递归地执行此操作,这是一个成熟的习惯用法:

def allResults: Iterator[Result] = {
  def nextPage(pageId: String): Iterator[Result] = {
    val page = invoke api
    Iterator(page.results) ++ nextPage(page.nextPageId)
  }
  val firstPage = invoke api
  Iterator(firstPage.results) ++ nextPage(firstPage.nextPageId)
}

这个成语堆栈安全吗?还是有其他需要担心的效率问题?

【问题讨论】:

    标签: scala iterator


    【解决方案1】:

    我相信这是堆栈安全的,特别是因为 ++ 方法采用按名称调用的参数,正如您所提到的。

    这适用于迭代器和流,但不适用于列表和地图等“非惰性”集合。

    在这些情况下,您应该使用累加器并使用 @tailrec 注释您的方法,以确保您不会像 https://stackoverflow.com/a/3114248/854793 那样使用比预期更多的堆栈

    【讨论】:

      【解决方案2】:

      在使用 Iterator.++ 时,我在 Scala 2.11.11 上收到 StackOverflowError,但在使用 Stream.#:: 时却没有。我认为这一定是 Scala 2.11.11 中Iterator.++ 中的一个错误。在 Scala 2.12.2 上都可以工作:

      def iter(n: Int): Iterator[Int] = if (n <= 0) Iterator.empty else { Iterator.single(n) ++ iter(n - 1) } iter(100000).foreach(print)

      这会在 Scala 2.11.11 上导致 StackOverflowError,但在 Scala 2.12.2 上却可以正常工作。使用Stream.#:: 也适用于两者。也许这是 Scala 2.11.11 中的一个错误?

      def stream(n: Int): Stream[Int] = if (n <= 0) Stream.empty else { n #:: stream(n - 1) } stream(1000000).foreach(print)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-02
        • 2014-12-10
        • 2017-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-18
        相关资源
        最近更新 更多