Scala For-Comprehension:如果未来失败,如何恢复和继续

Scala For-Comprehension: How to Recover and Continue If a Future Fails

给定以下 List 个整数...

val l = List(1, 2, 3)

...我需要在每个元素上调用 return 一个 Future 的 2 个方法并获得以下结果:

Future(Some(1), Some(2), Some(3))

下面是我的尝试:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def f1(i: Int) = Future(i)
def f2(i: Int) = Future { if (i % 2 == 0) throw new Exception else i }

val l = List(1, 2, 3)

val results = Future.sequence(l.map { i =
  val f = for {
    r1 <- f1(i)
    r2 <- f2(i) // this throws an exception if i is even
  } yield Some(r1)

  f.recoverWith {
    case e => None
  }
})

如果f2失败,我想恢复并继续剩下的元素。上面的代码不起作用,因为永远不会调用 recoverWith,即使 f2 失败。

f2失败时如何恢复,最终结果是这样的?

Future(Some(1), None, Some(3))

第二个元素应该是 None 因为当输入整数为偶数(即 2)时 f2 失败。

recoverWith 的输出类型为 Future 时,它工作正常。

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def f1(i: Int) = Future(i)
def f2(i: Int) = Future { if (i % 2 == 0) throw new Exception else i }

val l = List(1, 2, 3)

val results = Future.sequence(l.map { i =>
  val f = for {
    r1 <- f1(i)
    r2 <- f2(i) // this might throw an exception
  } yield Some(r1)

  f.recoverWith {
    case e => Future { println("Called recover " + i); None } // wrapped in Future
  }
})
results onComplete println 

结果:

// Called recover 2
// Success(List(Some(1), None, Some(3))       

// tried with scala version: 2.10.4

recoverWith 应该 return 一个 Future 的东西,所以你的例子甚至不会编译。

您可以改用recover

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def f1(i: Int) = Future(i)
def f2(i: Int) = Future { if (i % 2 == 0) throw new Exception else i }
val l = List(1, 2, 3)

val results = Future.sequence(l.map { i =>
  val f = for {
    r1 <- f1(i)
    r2 <- f2(i) // this throws an exception if i is even
  } yield Some(r1)

  f.recover { case _ => None }
})

另外,在你的具体例子中你甚至没有使用 r2,所以你可以只做

val results = Future.sequence(l.map { i =>
  f1(i).map(Some(_)).recover { case _ => None }
})