无法从多个不同类型的 Futures 组合 Scala Future

having trouble composing Scala Future from multiple Futures of different types

我有两个函数:一个 returns a Future[Thing Or Exception] 和另一个 returns Future[Boolean。我想要一个同时调用 returns Future[Thing Or Exception] 的函数。如果布尔函数 returns false 我想 return 一个异常,否则 return 另一个函数。

我有这样的代码,但是 a) 我讨厌演员表和 b) 当 "boolean gets true" 路径上的 运行 时,当我最终 Await.result 在 return 在我的测试代码中:"Promise$DefaultPromise cannot be cast to org.scalatic.Or".

def thingFuture: Future[Thing Or Exception]
def boolFuture: Future[Boolean]

def combineFutures: Future[Thing Or Exception] = {
   val result = boolFuture.map {x =>
     x match {
      case true => thingFuture
      case false => Exception
     }
   }
   // without the cast compiler says result is of type Future[Object]
   result.asInstanceOf[Future[Thing Or Exception]]
}

我也试过了,但它在成功路径上得到了同样的 Promise 错误

def combineFutures: Future[Thing Or Exception] = {
   val result = boolFuture.map {x =>
     x match {
       case true => thingFuture.map { y =>
         y match {
           case Good(thing) => thing
           case Bad(exception) => exception
         }
       case false => Exception
     }
   }
}

谁能告诉我如何组合两个 return 类型的期货?谢谢!

如果发生异常,每个 future 都可以以失败状态完成,因此您可以简单地 return "happy path" 中的 thingFuture 并在 boolean 为 false 的情况下抛出异常。这将 return 一个具有基础异常的 Future.failed

val result = boolFuture.flatMap {x =>
  x match {
    case true => thingFuture
    case false => throw new Exception("whatever")
  }
}

请注意 flatMap 而不是 map。因为我们将一个未来的潜在价值映射到另一个未来,通过使用简单的 map 我们最终会得到 Future[Future[Thing]].

另请注意,除了抛出异常外,您还可以 return 一个 Future.failed(throw new Exception("whatever")) 并且结果是相同的 - 在这两种情况下您都会遇到失败的未来。

编辑:我刚刚意识到 Or 来自 scalactic,我从未使用过它,但理念保持不变。你需要 flatMap 你的布尔未来和你的 ThingOrException 未来才能结束 Future[ThingOrException]。如果你发现自己处于需要 flatMap 一个 Future 的情况,但其中一个 case 子句 return 是一个普通值(例如,如果是 true return Future[Thing],如果of false return just Exception) 然后你可以将普通值包装到未来。这样所有分支 return 一个 future 和 flatMap 都会正常工作。例如:

val someOtherFuture = Future(43)
val someOrdinaryValue = 44

Future(someInteger).flatMap {
  case 42 => someOtherFuture
  case _  => Future(someOrdinaryValue)
}

为了稍微简化运行时机制,您也可以写成Future.successful(someOrdinaryValue),这样就不会启动后台计算。

据我从 Scalatic 文档中得知,您可以通过 Good(Right)Bad(Left).

获得 Right Or Left 的实例

这意味着组合可能看起来像这样:

boolFuture.flatMap(b => if (b) thingFuture else Future.successful(Bad(new Exception())))

类型应统一为Future[Or[Thing, Exception]]