我有一个Web请求的未来结果,我需要计算它的大小。如果当前响应有项目,我需要再次请求获取下一组,等等。如果当前响应为空,我就完成了。
我现在的代码:
def list(prefix: String, lastItem: Option[String] = None, last: Seq[BucketItem] = Nil): Future[Iterable[BucketItem]] = {
Logger.debug(s"list :: prefix=$prefix, lastItem=$lastItem, lastItems=${last.size}")
for {
current <- s3.get(name, None, Some(prefix), delimiter, lastItem, None) map listResponse // type is Seq[BucketItem]
next <- list(prefix, Some(current.last.name), last ++ current) if !(current.isEmpty)
} yield last ++ current
}
这似乎工作正常,直到当前没有任何更多的元素,并且我得到一个NoSuchElementException试图获取current.last.name
我理解条件if!(current.isEmpty)扩展为过滤器,所以这不是我真正想要的。我想要的是:
sequentially:
eval current
if current has more items, recursively call list to get the next set of items
yield the concatenated sequence of the right type (all the previous entries plus the last0
我在这里使用for comprehension来轻松处理收集期货(至少这是我过去做过的方式)。任何指导/事情要阅读?我对scala很新,所以请保持温和。
答案 0 :(得分:0)
我认为您的过滤器位于错误的位置,这应该有效:
def list(prefix: String, lastItem: Option[String] = None, last: Seq[BucketItem] = Nil): Future[Iterable[BucketItem]] = {
Logger.debug(s"list :: prefix=$prefix, lastItem=$lastItem, lastItems=${last.size}")
for {
current <- s3.get(name, None, Some(prefix), delimiter, lastItem, None) map listResponse // type is Seq[BucketItem]
if !current.isEmpty
next <- list(prefix, Some(current.last.name), last ++ current)
} yield last ++ current
}
答案 1 :(得分:0)
您没有使用变量next
,因此您无法在第一个之后获得s3.get
次调用的结果。此外,您的if !(current.isEmpty)
会在withFilter
值上调用Future
,这可能会导致失败的Future
,这不是您想要的。
这是一个更简单的解决方案:
def list(prefix: String, lastItem: Option[String] = None, accum: Seq[BucketItem] = Vector()): Future[Iterable[BucketItem]] = {
s3.get(name, None, Some(prefix), delimiter, lastItem, None) flatMap { current =>
if (current.isEmpty)
Future.successful(accum)
else
list(prefix, bucketItems.last.name, accum ++ current)
}
}
for-comprehension只能代表map
嵌套在flatMap
次调用(或foreach
彼此内部的withFilter
次调用)中,并且会散布到flatMap
的调用。我们所需要的只是对for
的一次调用,因此List
没有用。
我还将Vector
替换为{{1}},在将元素追加到最后时效果更好。