假设您使用的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)
}
这个成语是否安全?或者还有其他效率问题需要担心吗?
答案 0 :(得分:2)
我相信这是堆栈安全的,特别是因为++
方法采用了call-by-name参数,正如你所提到的那样。
这适用于Iterators和Streams,但不适用于"非懒惰"列表和地图等集合。
在这些情况下,您应该使用累加器并使用@tailrec
注释您的方法,以确保您不会像https://stackoverflow.com/a/3114248/854793中那样使用比预期更多的堆栈
答案 1 :(得分:0)
使用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)