2013-07-25 13 views
21

Nell'esempio qui sotto ho l'eccezione java.util.NoSuchElementException: Future.filter predicate is not satisfiedScala futuro con filtro per la comprensione

voglio avere il risultato Future(Test2) quando il controllo if(i == 2) fallisce. Come gestisco il filtro/se all'interno di una comprensione che riguarda la composizione dei future?

Di seguito è un esempio semplificato che funziona in Scala REPL.

Codice:

import scala.concurrent.Future 
import scala.util.{ Try, Success, Failure } 
import scala.concurrent.ExecutionContext.Implicits.global 

val f1 = Future(1) 
val f2 = for { 
    i <- f1 
    if(i == 2) 
} yield "Test1" 
f2.recover{ case _ => "Test2" } 
f2.value 

risposta

11

Nella tua for-comprehension, si sta filtrando dai i == 2. Poiché il valore di f1 non è due, non produrrà uno Success ma invece uno Failure. Il predicato del filtro non è soddisfatto, come ti dice il tuo messaggio errror. Tuttavia, f2.recover restituisce un nuovo Future. Il valore di f2 non è manipolato. Memorizza ancora il Failure. Questo è il motivo per cui ricevi il messaggio di errore quando chiami f2.value.

L'unica alternativa che posso pensare sarebbe utilizzare un else nel tuo for-comprehension come mostrato here.

val f2 = for (i <- f1) yield { 
    if (i == 2) "Test1" 
    else "Test2" 
} 
f2.value 

Ciò restituirà Some(Success(Test2)) come f3.value fa.

+0

Tuttavia, se f2 non riesce a causa di "i <- f1" in errore, il risultato non sarà "Test2" ma sarà comunque un errore. –

8

Naturalmente ho capito una soluzione di me stesso. Forse ci sono soluzioni migliori, più idiomatiche?

import scala.concurrent.Future 
import scala.util.{ Try, Success, Failure } 
import scala.concurrent.ExecutionContext.Implicits.global 

val f1 = Future(1) 
val f2 = for { 
    i <- f1 
    if(i == 2) 
} yield "Test1" 
val f3 = f2.recover{ case _ => "Test2" } 
// OR val f3 = f2.fallbackTo(Future("Test2")) 
f3.value 
+1

E 'menzionato nei documenti così: http://docs.scala-lang.org/overviews/core/futures.html#functional_composition_and_forcomprehensions no quando prendo una seconda occhiata. – Magnus

+1

Penso che usare 'recover' qui sia ok. Se si desidera che il ripristino si applichi solo all'eccezione basata sul predicato del filtro, è necessario modificare il 'caso _' in' caso ex: NoSuchElementException' dove 'NoSuchElementException' deriva da' java.util'. – cmbaxter

+0

Jürgen: Questa è una domanda di sei mesi, il codice sopra riportato è un esempio preso da una sessione REPL, quindi è orientato alla chiarezza. Stai commentando che puoi mettere le parentesi attorno alle istruzioni in Scala? Non vedo quale sia il tuo contributo qui. – Magnus

27

Questa è una soluzione più idiomatica, secondo me. Questa funzione di predicato crea un Future[Unit] o un futuro non riuscito contenente l'eccezione. Per il tuo esempio, ciò risulterebbe in uno Success("Test1") o Failure(Exception("Test2")). Questo è leggermente diverso da "Test1" e "Test2", ma trovo questa sintassi più utile.

def predicate(condition: Boolean)(fail: Exception): Future[Unit] = 
    if (condition) Future(()) else Future.failed(fail) 

si utilizza in questo modo:

val f2 = for { 
    i <- f1 
    _ <- predicate(i == 2)(new Exception("Test2")) 
    j <- f3 // f3 will only run if the predicate is true 
} yield "Test1" 
+1

Questo è stato un consiglio molto utile. Grazie! – Tommi

+0

Molto più chiaro, grazie! – Artemis

Problemi correlati