如何在scala中收集分页结果

如何在scala中收集分页结果,scala,pagination,Scala,Pagination,我试图通过尝试在Scala中执行以下逻辑来收集分页结果,但不幸失败: def python_version(): cursor books, cursor = fetch_results() while (cursor!=null) { new_books = fetch_results(cursor) books = books + new_books } return books def fetch_results

我试图通过尝试在Scala中执行以下逻辑来收集分页结果,但不幸失败:

def python_version():
    cursor 
    books, cursor = fetch_results()
    while (cursor!=null) {
        new_books = fetch_results(cursor)
        books = books + new_books
    }
    return books


def fetch_results(cursor=None):
    #do some fetchings...
    return books, next_cursor

也许是这样的:

 Iterator.iterate(fetch_results()) { 
   case (_, None) => (Nil, None)
   case (books, cursor) => fetch_results(cursor)
 }.map(_._1).takeWhile(_.nonEmpty).flatten.toList`
.iterate
将第一个参数作为迭代器的初始元素,第二个参数是一个函数,给定前一个元素,该函数计算下一个元素。 因此,这将创建一个元组迭代器
(Seq[Book],Cursor)
,从最初返回的
fetch\u results
开始,然后继续获取更多结果,并将其累加,直到
nextCursor
None
(我使用了
None
而不是null,因为null是邪恶的,不应该在正常语言中使用,比如scala,它提供了足够的工具来避免它们)

然后,
.map(u._1)
丢弃游标(不再需要它们),因此我们现在有了一个页面迭代器,
.takeWhile
首先截断迭代器
页面为空,然后将所有内部
序列连接在一起,最后
toList
具体化所有元素,并返回整个图书列表。

这里有一个使用递归函数的替代解决方案,它避免了可变值:

def fetchResults(c: Option[Cursor]=None): (List[Book], Option[Cursor]) = ...

def fetchAllResults(): List[Book] = {
  @tailrec
  def loop(cursor: Option[Cursor], res: List[Book]): List[Book] = {
    val (books, newCursor) = fetchResults(cursor)
    val newBooks = res ::: books

    newCursor match {
      case Some(_) =>
        loop(newCursor, newBooks)
      case None =>
        newBooks
    }
  }

  loop(None, Nil)
}
这是Scala中递归函数的一个相当标准的模式,实际递归在内部函数中完成。上一次迭代的结果被传递到下一次迭代,然后从函数返回。这意味着
循环
是一个尾部递归函数,可以由编译器优化为<代码>while
循环。(如果这不是尾部递归,则
@tailrec
注释告诉编译器发出警告)