2014-10-14 9 views
13

Sto scrivendo un'applicazione Scala utilizzando il driver ReactiveMongo. I metodi che accedono al db restituiscono sempre Future[T]. I seguenti pezzi di codice sono equivalenti?Qual è la differenza tra onComplete e flatMap of Future?

(con onComplete)

val results: Future[List[Tag]] = Tags.all.toList 
results onComplete { 
    case Success(list) => //do something with list 
    case Failure(t) => //throw the error 
} 

(con flatMap)

Tags.all.toList.flatMap(list => //do something with list) 

Qual è la differenza?

Il flatMap non lancia il guasto ?? E lo flatMap è un callback come onComplete o attendere fino a quando l'istruzione Tags.all.toList non viene completata?

+0

È evidente dalla firma: allo stesso modo prova monad, 'flatMap' non riguarda i guasti. È ciò di cui tratta la monade: si passa qualsiasi errore intatto e si applicano le operazioni solo se non ci sono errori nella pipe. Solo alla fine ti consigliamo di cogliere entrambi gli errori e i successi –

risposta

27

In caso di dubbio, seguire i tipi.

onComplete rendimenti Unit, che permette di fare qualcosa con il risultato Future, ma non restituirà un valore

flatMap permettono di fare qualcosa con la lista e restituire una nuova Future

Quindi, flatMap è molto più potente in quanto consente di concatenare più futuri, fare qualcosa con i loro valori lungo la strada e gestire il caso di fallimento solo alla fine. Per usare le parole di Erik Meijer: "ti guida attraverso il sentiero felice".

Così, per esempio si può fare

val finalFuture = results 
.flatMap(x => /* do something and return a future */) 
.flatMap(y => /* do something else and return a future */) 
.flatMap(z => /* do something else and return a future */) 
.map(myresult => /* do something */) 

Se qualcosa va storto lungo la strada, la catena è rotto presto e si otterrà si è verificato il primo errore.

Questo permette una sintassi ancora più bello

val finalFuture = for { 
    x <- results 
    y <- /* do something and return a future */ 
    z <- /* do something and return a future */ 
} yield something(z) 

Se è necessario per gestire il caso fallimento, è ora possibile utilizzare onComplete, o - ancora meglio - semplicemente restituire il Future in quanto contiene già le informazioni sul fatto il calcolo asincrono è riuscito o meno.

+1

Ottima risposta. Mi ha aiutato oggi –

+1

"In caso di dubbi, segui i tipi." è una buona regola empirica – mulya

+0

In questo esempio, finalFuture restituisce un futuro [Nothing] indipendentemente dal tipo di qualcosa (z). Che cosa succede se è necessario passare qualcosa (z): T a qualcosa che si aspetta T? – Azeli

Problemi correlati