Scala:NoSuchElementException用于理解

时间:2014-04-23 01:09:43

标签: scala promise future for-comprehension

我有一个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很新,所以请保持温和。

2 个答案:

答案 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}},在将元素追加到最后时效果更好。