2015-08-03 8 views
1

Возможно ли «инвертировать» будущее Scala?Invert a Scala Future

Иногда результат Будущего, являющегося Успехом, означает ошибку. В этом случае было бы неплохо перевернуть Будущее, то есть вызвать функцию, которая возвращает Будущее, которая преуспевает с указанным значением, если исходное Будущее выходит из строя и терпит неудачу с указанной ошибкой, если исходное Будущее будет успешным.

def flip[T](original: Future[T])(value: => T)(error: Throwable): Future[T] = ??? 
+0

Не могли бы вы привести пример, когда успех означает ошибку? – LuxuryMode

+0

Какой вариант использования этой функции? –

+0

позволяет сказать, что я пишу службу, которая создает что-то только в том случае, если она еще не существует ... если она существует, я получаю сообщение об ошибке, если нет - я приступаю к результату. (Я думаю, мне, возможно, придется связать его и с другим будущим) – Developer

ответ

8
def craziness[A](future: Future[A])(default : => A)(error: Throwable)(implicit ec: ExecutionContext): Future[A] = { 
    val p = Promise[A]() 
    import scala.util.{Success, Failure, Try} 
    future.onComplete { 
     case _: Success[_] => p.failure(error) 
     case _: Failure[_] => p.complete(Try(default)) 
    } 
    p.future 
    } 

Вот РЕПЛ сессии, в которой он работает:

scala> val f1 = craziness[String](Future("hello!"))("my crazy default")(new Throwable("boom")) 
f1: scala.concurrent.Future[String] = [email protected] 

scala> f1 onComplete { println } 
Failure(java.lang.Throwable: boom) 

scala> val f2 = craziness[String](Future(throw new Exception("boom!")))("my crazy default")(new Throwable("boom")) 
f2: scala.concurrent.Future[String] = [email protected] 

scala> f2 onComplete { println } 
Success(my crazy default) 

EDIT:

для полноты def craziness[A](future: Future[A]) следует, вероятно, def craziness[A](future: => Future[A])

+0

К сожалению, это решение неверно. если 'default' бросает ... –

1

Я думаю, что вы после recover и recoverWith Конструкции. Вот быстрый сеанс REPL, чтобы показать его использование.

$ scala 
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> import scala.concurrent.Future 
import scala.concurrent.Future 

scala> import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.ExecutionContext.Implicits.global 

scala> val failFuture = Future(sys.error("BOOM")) 
failFuture: scala.concurrent.Future[Nothing] = [email protected] 

scala> val defaultValue = 100 
defaultValue: Int = 100 

scala> val futureRecoveredWithDefaultFuture = failFuture.recoverWith { case e: RuntimeException => Future.successful(defaultValue) } 
futureRecoveredWithDefaultFuture: scala.concurrent.Future[Int] = [email protected] 

scala> val futureRecoveredWithDefaultValue = failFuture.recover { case e: RuntimeException => defaultValue } 
futureRecoveredWithDefaultValue: scala.concurrent.Future[Int] = [email protected] 

Проверка, если это действительно работает:

scala> import scala.concurrent.duration._ 
import scala.concurrent.duration._ 

scala> import scala.concurrent.Await 
import scala.concurrent.Await 

scala> val res1 = Await.result(futureRecoveredWithDefaultFuture, 1.second) 
res1: Int = 100 

scala> val res2 = Await.result(futureRecoveredWithDefaultValue, 1.second) 
res2: Int = 100 
0

В Scala 2.12 вы сможете использовать transform и transformWith сделать это тривиально.

Но до тех пор это должно получить вас там:

implicit class InvertFuture[T](val fut: Future[T]) extends AnyVal { 
    def flip(recover: Throwable => T)(fail: T => Throwable)(implicit ec: ExecutionContext): Future[T] = 
     fut.recover({ case t => recover(t) }).map(t => throw fail(t)) 
} 

// And usage: 

scala> Future(1).flip(_ => 2)(_ => throw new IllegalStateException("ohnoes!")) onComplete println 
Failure(java.lang.IllegalStateException: ohnoes!) 
Смежные вопросы