Последовательно объедините произвольное количество фьючерсов в Scala

Я новичок в scala, и я пытаюсь объединить несколько фьючерсов в scala 2.10RC3. Futures должен выполняться в последовательном порядке. В документе Scala SIP14 метод andThen определяется для выполнения фьючерсов в последовательном порядке. Я использовал этот метод для объединения нескольких Futures (см. Пример ниже). Я ожидал, что он напечатает 6, но на самом деле результат 0. Что я здесь делаю неправильно? У меня есть два вопроса:

Во-первых, почему результат 0. Во-вторых, как я могу объединить несколько Futures, так что выполнение второго Future не запускается до того, как будет завершено первое Future.

val intList = List(1, 2, 3)

val sumOfIntFuture = intList.foldLeft(Future { 0 }) {
 case (future, i) => future andThen {
  case Success(result) => result + i 
  case Failure(e) => println(e)
 }
}

sumOfIntFuture onSuccess { case x => println(x) }

Ответ 1

andThen - для побочных эффектов. Он позволяет указать некоторые действия, которые необходимо выполнить после завершения будущего, и до того, как он будет использован для чего-то еще.

Использование карты:

scala> List(1, 2, 3).foldLeft(Future { 0 }) {
     |  case (future, i) => future map { _ + i }
     | } onSuccess { case x => println(x) }
6

Ответ 2

Мне нравится этот общий подход:

trait FutureImplicits {

  class SeriallyPimp[T, V](futures: Seq[T]) {
    def serially(f: T => Future[V])(implicit ec: ExecutionContext): Future[Seq[V]] = {
      val buf = ListBuffer.empty[V]
      buf.sizeHint(futures.size)

      futures.foldLeft(Future.successful(buf)) { (previousFuture, next) =>
        for {
          previousResults <- previousFuture
          nextResult <- f(next)
        } yield previousResults += nextResult
      }
    }
  }

  implicit def toSeriallyPimp[T, V](xs: Seq[T]): SeriallyPimp[T, V] =
    new SeriallyPimp(xs)

}

Затем смешайте приведенную выше черту и используйте ее следующим образом:

val elems: Seq[Elem] = ???
val save: Elem => Future[Result] = ???
val f: Future[Seq[Result]] = elems serially save

Этот код можно улучшить, чтобы сохранить тип входной коллекции. См. эту статью.