1

有一个 REST api,它返回一个带有 json 列表(命名结果)的 json 和一个指向下一批结果的 url(对于最后一个“页面”,这个 url 等于 null)。我想汇总整个结果(将所有 json 列表连接成一个)。我正在使用 spray-client 来执行 GET 请求,这就是我想出的:

  val request: HttpRequest => Future[MyResponse] = sendReceive ~> unmarshal[MyResponse]
  def getCandidatesStartingFrom(url: String): Future[List[Candidate]] =
      request(Get(url)).flatMap {
        response =>
            val next = response.next match {
              case Some(nextUrl) => getCandidatesStartingFrom(nextUrl)
              case None => Future.successful(Nil)
            }
            next.map(response.results ++ _)
      }

我的问题是:有没有办法让它更实用?(避免递归或使其尾递归?)。甚至,spray 是否支持惯用的这种聚合?

4

2 回答 2

0
request(Get(url)).flatMap {
        response =>
            val next = response.next match {
              case Some(nextUrl) => getCandidatesStartingFrom(nextUrl)
              case None => Future.successful(Nil)
            }
            next.map(response.results ++ _)
      }

可以写成如下。但这并没有太大的进步。

for{   
  response <- request(Get(url))   
  nextUrl <- response.next
               .map(getCandidatesStartingFrom)
               .getOrElse(Future.successful(Nil)) 
} yield response.results ++ nextUrl
于 2013-12-14T21:34:35.417 回答
0

它目前不是递归的。您的“递归”调用getCandidatesStartingFrom实际上不在父调用的调用堆栈中getCandidatesStartingFrom,而是在传递给的匿名 lambda 中flatMap

getCandidatesStartingFrom

  1. 要求 spray 开始一个 HTTP 请求(立即返回一个未来)
  2. 使用匿名函数调用flatMap该 future 以在它完成时运行。这也立即返回了一个未来。
  3. 将未来返回给调用者
于 2013-12-14T21:42:36.213 回答