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 }
})
给定以下 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 }
})