处理失败的"未来"

Kev*_*ith 3 scala

给出以下两种方法:

def f: Future[Int] = Future { 10 }
def g: Future[Int] = Future { 5 }
Run Code Online (Sandbox Code Playgroud)

我想写一下:

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

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

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

scala> for { 
     |   a <- f
     |   b <- g
     | } yield (a+b)
res2: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@34f5090e
Run Code Online (Sandbox Code Playgroud)

现在,我会打电话Await.result来阻止它完成.

scala> import scala.concurrent.duration._
import scala.concurrent.duration._
Run Code Online (Sandbox Code Playgroud)

正如所料,我得到了15,因为Await.result拿了一个Future[Int]并且退了回来Int.

scala> Await.result(res2, 5.seconds)
res6: Int = 15
Run Code Online (Sandbox Code Playgroud)

recoverFn为失败的未来定义一个:

scala> val recoverFn: PartialFunction[Throwable, Future[Int]] = 
    { case _ => Future{0} }
recoverFn: PartialFunction[Throwable,scala.concurrent.Future[Int]] = <function1>
Run Code Online (Sandbox Code Playgroud)

我尝试定义failedFuture:

scala> def failedFuture: Future[Int] = Future { 666 }.failed.recoverWith{ recoverFn }
<console>:20: error: type mismatch;
 found   : scala.concurrent.Future[Any]
 required: scala.concurrent.Future[Int]
       def failedFuture: Future[Int] = Future { 666 }.failed.recoverWith{ recoverFn }
                                                                        ^
Run Code Online (Sandbox Code Playgroud)

但是,我得到上面的编译时错误.

具体来说,我该如何修复此错误?一般来说,Future#recoverWith通常是如何Future处理失败的?

Mic*_*jac 8

问题是Future#failed 总是回归Future[Throwable].它的目的不是简单地失败一个Future,而是返回一个失败的投影的那个Future.这意味着如果原始Future失败,它将转换为成功 Future保存异常.如果原来Future成功了,那么它就会失败,并拥有一个NoSuchElementException.你得到的错误是因为你基本上正在恢复Future[Throwable]a Future[Int],其中a的上限最小Future[Any].

如果您只是尝试使用失败的Futures,请尝试以下方法:

scala> Future.failed[Int](new Exception("???")).recoverWith(recoverFn)
res4: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@6933711b

scala> res4.value.get
res5: scala.util.Try[Int] = Success(0)
Run Code Online (Sandbox Code Playgroud)

没有任何问题recoverWith.