现代 scala 期货就像它们Either
包含一个成功的结果或一个Throwable
. 如果您在 scala 2.10 中重新访问此代码,我想您会发现这种情况非常愉快。
具体来说,scala.concurrent.Future[T]在技术上只是 "is-a" Awaitable[T]
,但_.onComplete
两者Await.ready(_, timeout).value.get
都将其结果呈现为scala.util.Try[T],这很像Either[Throwable, T]
它是结果或异常。
奇怪的是,_.transform
它需要两个映射函数,一个是 for T => U
,一个是 for Throwable => Throwable
and (除非我遗漏了什么)没有将未来映射为Try[T] => Try[U]
. Future
's.map
将允许您通过简单地在映射函数中抛出异常来将成功变为失败,但它仅将其用于原始Future
. 它.recover
,同样可以化失败为成功。如果您希望能够将成功更改为失败,反之亦然,您需要自己构建一些东西,它是_.map
和_.recover
或_.onComplete
用于链接到新的scala.concurrent.Promise[U]的组合,如下所示:
import scala.util.{Try, Success, Failure}
import scala.concurrent.{Future, Promise}
import scala.concurrent.ExecutionContext
def flexibleTransform[T,U](fut: Future[T])(f: Try[T] => Try[U])(implicit ec: ExecutionContext): Future[U] = {
val p = Promise[U]
fut.onComplete { res =>
val transformed = f(res)
p.complete(transformed)
}
p.future
}
这将像这样使用:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration.Duration.Inf
def doIt() {
val a: Future[Integer] = Future {
val r = scala.util.Random.nextInt
if (r % 2 == 0) {
throw new Exception("we don't like even numbers")
} else if (r % 3 == 0) {
throw new Exception("we don't like multiples of three")
} else {
r
}
}
val b: Future[String] = flexibleTransform(a) {
case Success(i) =>
if (i < 0) {
// turn negative successes into failures
Failure(new Exception("we don't like negative numbers"))
} else {
Success(i.toString)
}
case Failure(ex) =>
if (ex.getMessage.contains("three")) {
// nevermind about multiples of three being a problem; just make them all a word.
Success("three")
} else {
Failure(ex)
}
}
val msg = try {
"success: " + Await.result(b, Inf)
} catch {
case t: Throwable =>
"failure: " + t
}
println(msg)
}
for { _ <- 1 to 10 } doIt()
这会给出这样的结果:
failure: java.lang.Exception: we don't like even numbers
failure: java.lang.Exception: we don't like negative numbers
failure: java.lang.Exception: we don't like negative numbers
success: three
success: 1756800103
failure: java.lang.Exception: we don't like even numbers
success: 1869926843
success: three
failure: java.lang.Exception: we don't like even numbers
success: three
(或者你可以用隐式的def “拉皮条”Future
到 a中并创建一个成员函数,删除参数并简单地使用)RichFutureWithFlexibleTransform
flexibleTransform
fut
this
(更好的是获取Try[T] => Future[U]
并调用它,flexibleFlatMap
以便您可以在转换中执行异步操作)