问题
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