如何最好地处理Future.filter谓词不满足类型错误



我喜欢scala的类型安全性,但我一直遇到的一个运行时错误是

 Future.filter predicate is not satisfied

我明白我为什么会犯这个错误,只是想寻求如何最好地解决这个错误并优雅地处理它的建议,或者我做错了?

val r: Future[play.api.mvc.Result] = for {
  account <- accountServer.get(...)
  if account.isConfirmed
  orders <- orderService.get(account, ...)
} yield {
  ...
}

如果帐户没有得到确认,我将得到上述错误。

我本以为,由于过滤器有可能失败,scala会使收益率返回值成为Option。不

filterFuture没有意义,因为类型系统不知道else情况下返回什么,所以依赖它(通过使用if保护)是不安全的。但你可以在一个内这样做,以便理解,以实现相同的事情:

val r: Future[play.api.mvc.Result] = for {
  account <- accountServer.get(...)
  orders <- if (account.isConfirmed) orderService.get(account, ...) 
            else Future.successful(Seq.empty) 
} yield {
  ...
}

(正如Jean-Logeart的回答,但在理解范围内)

您可能想要使用一个简单的flatMap,在其中您可以指定一个else的情况:

val orders = accountServer.get(...)
                          .flatMap { account => 
                            if(account.isConfirmed) orderService.get(account, ...)
                            else Future.successful(Seq.empty)
                          }

用于理解的A只是foreachmapflatMapfilter等链的语法糖。当您编写if account.isConfirmed时,这相当于使用Future的filter方法。

已解析的Future的值包含在Try中,Try可以采取成功或失败的形式。(将其与Option进行比较,后者可以采取Some或None的形式。)

就像Option的filter在包含的值使谓词失败时将Some转换为None一样,Future/Try filter方法将Success转换为Failure。如果您查看Future.filter或Try.filter的实现,这是通过返回一个Failure来完成的,其中包含您提到的predicate is not satisfied消息的new NoSuchElementException

因此,错误消息本身完全是经过设计的,并且与类型系统一致。理解过程中的任何一步都只会投射出另一个未来,所以写if account.isConfirmed要么通过筛选,要么失败。

这就是为什么Scala在使用if/filter时不会将Future[Result]更改为Future[Option[Result]]的原因。如果你想产生一个成功的包含Future的Option或一个空的Seq,你必须明确地这样做(正如Jean Logeart和Alvaro Carrasco的回答所示)。

最新更新