2012-12-12 7 views
10

Ich bin neu in Scala und ich versuche, mehrere Futures in Scala 2.10RC3 zu kombinieren. Die Futures sollte in sequentieller Reihenfolge ausgeführt werden. In dem Dokument Scala SIP14 ist die Methode andThen definiert, um Futures in sequentieller Reihenfolge auszuführen. Ich habe diese Methode verwendet, um mehrere Futures zu kombinieren (siehe Beispiel unten). Meine Erwartung war, dass es 6 druckt, aber tatsächlich ist das Ergebnis 0. Was mache ich hier falsch? Ich habe zwei Fragen:Sequentiell kombinieren beliebige Anzahl von Futures in Scala

Erstens, warum ist das Ergebnis 0. Zweitens, wie kann ich mehrere Futures kombinieren, so dass die Ausführung der zweiten Future nicht startet, bevor die erste Future fertig ist.

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) } 

Antwort

12

andThen ist für Nebenwirkungen. Es ermöglicht Ihnen, einige Aktionen anzugeben, die ausgeführt werden sollen, nachdem die Zukunft abgeschlossen ist und bevor sie für etwas anderes verwendet wurde.

Verwenden Karte:

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

Danke! Genau das habe ich gebraucht. – Chrisse

+0

+1 Das hat mir sehr geholfen! – pvorb

2

Ich mag diesen allgemeinen Ansatz:

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) 

} 

Dann mischen in dem obigen Merkmal und es wie folgt verwendet werden:

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

Dieser Code könnte verbessert werden, um den Eingabesammeltyp beizubehalten. Siehe zum Beispiel this Artikel.