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

时间:2015-10-04 15:38:31

标签: scala future for-comprehension

给出以下List个整数...

val l = List(1, 2, 3)

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

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失败。

2 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:3)

recoverWith应返回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 }
})