简体   繁体   English

无法从多个不同类型的期货组成Scala期货

[英]having trouble composing Scala Future from multiple Futures of different types

I have two functions: one returns a Future[Thing Or Exception] and another that returns Future[Boolean . 我有两个函数:一个返回Future[Thing Or Exception] ,另一个返回Future[Boolean I want a function that calls both and returns Future[Thing Or Exception] . 我想要一个同时调用这两个函数并返回Future[Thing Or Exception]的函数。 If the boolean function returns false I want to return an exception, else the return of the other function. 如果布尔函数返回false,我想返回一个异常,否则返回另一个函数。

I have code like this but a) I hate the cast and b) when run on the "boolean gets true" path I get this error when I eventually Await.result on the return in my test code: "Promise$DefaultPromise cannot be cast to org.scalatic.Or" . 我有这样的代码,但是a)我讨厌转换,并且b)在“布尔值成真”路径上运行时,当我最终在测试代码中返回Await.result时收到此错误: "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]]
}

I've also tried this but it gets the same Promise error on the success path 我也尝试过此方法,但成功路径上会出现相同的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
     }
   }
}

Can anyone tell me how to compose two futures with different return types? 谁能告诉我如何组合两种具有不同收益类型的期货吗? Thanks! 谢谢!

Every future can be completed with failed state in case exception has occurred, so you can simply return thingFuture in the "happy path" and throw an exception in case boolean is false. 万一发生异常,每一个未来都可以以失败状态完成,因此您可以简单地在“快乐之路”中返回thingFuture,并在布尔值为假的情况下抛出异常。 This will return a Future.failed with the underlying exception. 这将返回Future.failed并带有基础异常。

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

Note the flatMap instead of map . 注意flatMap而不是map Because we map the underlying value of one future into a yet another future, by using simple map we would wind up with Future[Future[Thing]] . 因为我们将一个未来的潜在价值映射到了另一个未来,所以通过使用简单的map我们将得出Future[Future[Thing]]

Also note that instead of throwing an exception, you could also return a Future.failed(throw new Exception("whatever")) and the result would be the same - in both case you get a failed future. 还要注意,除了抛出异常,您还可以返回Future.failed(throw new Exception("whatever")) ,结果将是相同的-在两种情况下,您都会遇到失败的未来。

EDIT: I just realized Or comes from scalactic, which I never used, but the philosophy remains the same. 编辑:我刚刚意识到Or来自标尺的,这是我从未使用过的,但是其原理仍然是相同的。 You need to flatMap your boolean future and your ThingOrException future in order to wind up with Future[ThingOrException] . 您需要flatMap您的布尔型Future[ThingOrException]ThingOrException future才能使用Future[ThingOrException] If you ever find yourself in a situation where you need to flatMap a Future, but one of the case clauses returns an ordinary value (eg in case of true return Future[Thing] , in case of false return just Exception ) then you can wrap the ordinary value into a future. 如果您发现自己需要FlatMap a Future,但是其中一个case子句返回一个普通值(例如,如果返回true,则返回Future[Thing] ,如果返回false,则返回Exception ),则可以包装普通价值带入未来。 This way all branches return a future and flatMap will work correctly. 这样,所有分支都返回一个future,flatMap将正常工作。 For example: 例如:

val someOtherFuture = Future(43)
val someOrdinaryValue = 44

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

In order to simplify things for the runtime machinery a bit, you can also write Future.successful(someOrdinaryValue) in which case no background computation is started. 为了稍微简化运行时机制,您还可以编写Future.successful(someOrdinaryValue)在这种情况下,不会启动后台计算。

As far as I can tell from Scalatic documentation, you can get an instance of Right Or Left by either Good(Right) or Bad(Left) . 据我从Scalatic文档中得知,您可以通过Good(Right)Bad(Left)获得Right Or Left的实例。

That means the composition can potentially look like this: 这意味着合成可能看起来像这样:

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

The types should unify to Future[Or[Thing, Exception]] 类型应统一为Future[Or[Thing, Exception]]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM