for comprehension scala filter future for-comprehension

comprehension - for scala



Scala Future con filtro para la comprensiĆ³n. (4)

En su for-comprehension , está filtrando por i == 2 . Debido a que el valor de f1 no es dos, no producirá un Success sino un Failure . El predicado del filtro no se cumple, como lo indica su mensaje de error. Sin embargo, f2.recover devuelve un nuevo Future . El valor de f2 no está manipulado. Todavía almacena el Failure . Esa es la razón por la que recibe el mensaje de error cuando llama a f2.value .

La única alternativa que se me ocurra sería usar otra else en su for-comprehension como se muestra here .

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

Esto devolverá Some(Success(Test2)) como lo hace su f3.value .

En el siguiente ejemplo, obtengo la excepción java.util.NoSuchElementException: Future.filter predicate is not satisfied

Quiero tener el resultado Future( Test2 ) cuando la verificación if( i == 2 ) falla. ¿Cómo manejo el filtro / si dentro de una comprensión que trata de componer futuros?

A continuación se muestra un ejemplo simplificado que funciona en el REPL de Scala.

Código:

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


Esta es una solución más idiomática, en mi opinión. Esta función de predicado crea una Future[Unit] o un futuro fallido que contiene su excepción. Para su ejemplo, esto resultaría en un Success("Test1") o un Failure(Exception("Test2")) . Esto es ligeramente diferente de "Test1" y "Test2", pero me parece que esta sintaxis es más útil.

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

Lo usas así:

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


Me gustó la idea de @pkinsky e hice algunas mejoras. Solté el código para crear un objeto de Exception como este:

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

shouldTrue función shouldTrue se implementa utilizando la biblioteca de sourcecode lihaoyi:

def shouldTrue(condition: sourcecode.Text[Boolean])(implicit enclosing: sourcecode.Enclosing, file: sourcecode.File, line: sourcecode.Line): Future[Unit] = if (condition.value) Future.successful( () ) else Future.failed(new Exception(s"${condition.source} returns false/n/tat ${file.value}:${line.value}"))

Entonces genera automáticamente un mensaje de excepción más significativo:

java.lang.Exception: i == 2 returns false at /path/to/example.scala:17


Por supuesto que yo mismo descubrí una solución. ¿Acaso hay soluciones mejores, más idiomáticas?

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