How to best handle Future.filter predicate is not satisfied type errors

故事扮演 提交于 2019-12-07 01:24:56

问题


I love how scala is type safe, but one runtime error I keep running into is

 Future.filter predicate is not satisfied

I can see why I am getting this error, just looking for advice on how to best work around this error and handle it gracefully or maybe I am doing this wrong?

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

If the account is not confirmed, I will get the above error.

I would have thought that since there is a potential for the filter to fail, that scala would then make the yield return value an Option. No?


回答1:


filter doesn't make sense for Future since the type system wouldn't know what to return for the else case, so it is unsafe to rely on it (by using an if-guard). But you can do this within a for-comprehension to achieve the same thing:

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

(as Jean Logeart's answer, but within a for-comprehension)




回答2:


You probably want to use a simple flatMap in which you can specify an else case:

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



回答3:


A for-comprehension is just syntax sugar for a chain of foreach, map, flatMap, filter, etc.. When you write if account.isConfirmed, this is equivalent to using Future's filter method.

The value of a resolved Future is contained in a Try, which can either take the form of a Success or a Failure. (Compare this with Option, which can either take the form of Some or None.)

Much like Option's filter converts a Some to a None if the value contained fails the predicate, Future/Try filter methods will convert a Success to a Failure. If you look at the implementation for Future.filter or Try.filter, this is done by returning a Failure with a new NoSuchElementException containing the predicate is not satisfied message you mentioned.

So, the error message itself is entirely by design, and consistent with the type system. Any step in the for-comprehension will only project another Future, so writing if account.isConfirmed will either project a Success if it passes the filter or a Failure if it does not.

This is the answer as to why Scala will not change the Future[Result] into Future[Option[Result]] when you use if/filter. If you would instead like to yield a successful Future containing Option or an empty Seq, you must do so explicitly (as seen in Jean Logeart's and Alvaro Carrasco's answers).



来源:https://stackoverflow.com/questions/34572730/how-to-best-handle-future-filter-predicate-is-not-satisfied-type-errors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!