[英]Scala Future with filter in for comprehension
In the example below I get the exception java.util.NoSuchElementException: Future.filter predicate is not satisfied
在下面的示例中,我得到异常
java.util.NoSuchElementException: Future.filter predicate is not satisfied
I want to have the result Future( Test2 )
when the check if( i == 2 )
fails. 当检查
if( i == 2 )
失败时,我想得到结果Future( Test2 )
。 How do I handle filter/if within a for comprehension that deals with composing futures? 我如何处理过滤器/如果处理组成期货的理解?
Below is a simplified example that works in the Scala REPL. 下面是一个在Scala REPL中工作的简化示例。
Code: 码:
import scala.concurrent.Future
import scala.util.{ Try, Success, Failure }
import scala.concurrent.ExecutionContext.Implicits.global
val f1 = Future( 1 )
val f2 = for {
i <- f1
if( i == 2 )
} yield "Test1"
f2.recover{ case _ => "Test2" }
f2.value
This is a more idiomatic solution, in my opinion. 在我看来,这是一个更惯用的解决方案。 This predicate function creates either a
Future[Unit]
or a failed future containing your exception. 此谓词函数创建
Future[Unit]
或包含异常的失败的future。 For your example, this would result in either a Success("Test1")
or a Failure(Exception("Test2"))
. 对于您的示例,这将导致
Success("Test1")
或Failure(Exception("Test2"))
。 This is slightly different from "Test1" and "Test2", but I find this syntax to be more useful. 这与“Test1”和“Test2”略有不同,但我发现这种语法更有用。
def predicate(condition: Boolean)(fail: Exception): Future[Unit] =
if (condition) Future( () ) else Future.failed(fail)
You use it like this: 你这样使用它:
val f2 = for {
i <- f1
_ <- predicate( i == 2 )(new Exception("Test2"))
j <- f3 // f3 will only run if the predicate is true
} yield "Test1"
In your for-comprehension
, you are filtering by i == 2
. 在你
for-comprehension
,你通过i == 2
过滤。 Because the value of f1
is not two, it will not yield a Success
but instead a Failure
. 因为
f1
的值不是两个,所以它不会产生Success
,而是产生Failure
。 The predicate of the filter is not satisfied, as your errror message tells you. 您的错误消息告诉您,过滤器的谓词不满足。 However,
f2.recover
returns a new Future
. 但是,
f2.recover
返回一个新的Future
。 The value of f2
is not manipulated. 不操纵
f2
的值。 It still stores the Failure
. 它仍然存储
Failure
。 That is the reason you get the error message when you call f2.value
. 这就是您在调用
f2.value
时收到错误消息的原因。
The only alternative I can think of would be using an else
in your for-comprehension
as shown here . 我能想到的唯一的替代办法是使用
else
在你for-comprehension
如图所示这里 。
val f2 = for ( i <- f1) yield {
if (i == 2) "Test1"
else "Test2"
}
f2.value
This will return Some(Success(Test2))
as your f3.value
does. 这将返回
Some(Success(Test2))
作为你的f3.value
。
Of course I figured out one solution myself. 当然,我自己想出了一个解决方案。 Perhaps there are better, more idiomatic, solutions?
也许有更好,更惯用的解决方案?
import scala.concurrent.Future
import scala.util.{ Try, Success, Failure }
import scala.concurrent.ExecutionContext.Implicits.global
val f1 = Future( 1 )
val f2 = for {
i <- f1
if( i == 2 )
} yield "Test1"
val f3 = f2.recover{ case _ => "Test2" }
// OR val f3 = f2.fallbackTo( Future( "Test2" ) )
f3.value
I liked @pkinsky 's idea, and made a bit of improvement. 我喜欢@pkinsky的想法,并做了一点改进。 I dropped code to create
Exception
object like this: 我删除了代码来创建这样的
Exception
对象:
val f2 = for {
i <- f1
_ <- shouldTrue( i == 2 )
j <- f3 // f3 will only run if the predicate is true
} yield "Test1"
shouldTrue
function is implemented using lihaoyi`s sourcecode library: shouldTrue
函数是使用lihaoyi的源代码库实现的:
def shouldTrue(condition: sourcecode.Text[Boolean])(implicit enclosing: sourcecode.Enclosing, file: sourcecode.File, line: sourcecode.Line): Future[Unit] =
if (condition.value) Future.successful( () ) else Future.failed(new Exception(s"${condition.source} returns false\n\tat ${file.value}:${line.value}"))
Then it automatically generates more meaningful exception message: 然后它会自动生成更有意义的异常消息:
java.lang.Exception: i == 2 returns false
at \path\to\example.scala:17
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.