积累期货的最佳方式

Best way to accumulate futures

假设我有一个 return 是 Future 的函数,根据这个函数的结果,我可能需要再次调用它或者我可能 return 立即。我需要将这些结果累积在一个列表中。我想定义一个 return 将此列表作为 Future 的函数。我有以下内容:

def foo: Future[Int] { ... }

def accum(i: Future[Int], l: List[Int]): Future[List[Int]] = i.map { i =>
    if (i >= max)
        l
    else 
        accum(foo, i :: l)
}

def test: Future[List[Int]] = accum(foo, List())

但是当然这不会编译,因为在映射中调用 accum() 需要 return 一个 List[Int] 而不是 Future[List[Int]]。正确的做法是什么?

我认为以下内容对您有用,

def foo: Future[Int] = ???

def accumulate( max: Int, f: () => Future[ Int ], list: List[ Int ] = List[ Int ]() ): Future[ List[ Int ] ] = {
  val intFuture = f()

  intFuture.flatMap( ( i: Int ) => {
    // if future is successfull
    if ( i < max ) {
      // If value less than max, keep on accumulating more 
      accumulate( max, f, list :+ i )
    }
    else {
      // If value not less than max, stop accumulating more
      // Just wrap the list in future and return
      val promiseOfList = Promise[ List[ Int ] ]()
      promiseOfList.complete( Success( list ) )
      promiseOfList.future
    }
  } ).fallbackTo( {
    // If this computation fails.... stop accumulating
    // Just wrap the list in future and return
    val promiseOfList = Promise[ List[ Int ] ]()
    promiseOfList.complete( Success( list ) )
    promiseOfList.future
  } )

}

val myListFuture = accumulate( max, foo )

始终return来自内部块的Future,并使用flatMap:

def accum(i: Future[Int], l: List[Int]): Future[List[Int]] =
  i.flatMap { i =>
    if (i >= max)
      Future.successful(l)
    else 
      accum(foo, i :: l)
  }

根据 foo 的来源,您可能还需要考虑例如scalaz 的 foldLeftM 而不是显式递归函数。