Scala Future 带有过滤器以供理解

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17869624/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:32:47  来源:igfitidea点击:

Scala Future with filter in for comprehension

scalafilterfuturefor-comprehension

提问by Magnus

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. How do I handle filter/if within a for comprehension that deals with composing futures?

我想Future( Test2 )在检查if( i == 2 )失败时得到结果。如何在处理编写期货的理解中处理过滤器/如果?

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

采纳答案by tgr

In your for-comprehension, you are filtering by i == 2. Because the value of f1is not two, it will not yield a Successbut instead a Failure. The predicate of the filter is not satisfied, as your errror message tells you. However, f2.recoverreturns a new Future. The value of f2is not manipulated. It still stores the Failure. That is the reason you get the error message when you call f2.value.

The only alternative I can think of would be using an elsein your for-comprehensionas shown here.

在您的 中for-comprehension,您正在过滤i == 2。因为的值f1不是二,它不会产生 aSuccess而是 a Failure。正如您的错误消息告诉您的那样,过滤器的谓词不满足。但是,f2.recover返回一个新的Future. 的值f2不被操纵。它仍然存储Failure. 这就是您在调用 时收到错误消息的原因f2.value

唯一的选择我能想到会被使用的elsefor-comprehension如图所示这里

val f2 = for ( i <- f1) yield {
  if (i == 2) "Test1"
  else "Test2"
}
f2.value

This will return Some(Success(Test2))as your f3.valuedoes.

这将Some(Success(Test2))像您f3.value一样返回。

回答by pkinsky

This is a more idiomatic solution, in my opinion. This predicate function creates either a Future[Unit]or a failed future containing your exception. For your example, this would result in either a Success("Test1")or a Failure(Exception("Test2")). This is slightly different from "Test1" and "Test2", but I find this syntax to be more useful.

在我看来,这是一个更惯用的解决方案。此谓词函数创建Future[Unit]包含您的异常的一个或一个失败的未来。对于您的示例,这将导致 aSuccess("Test1")或 a Failure(Exception("Test2"))。这与“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"

回答by Magnus

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

回答by pocorall

I liked @pkinsky 's idea, and made a bit of improvement. I dropped code to create Exceptionobject like this:

我喜欢@pkinsky 的想法,并做了一些改进。我删除了代码来创建这样的Exception对象:

val f2 = for {
  i <- f1
  _ <- shouldTrue( i == 2 )
  j <- f3  // f3 will only run if the predicate is true
} yield "Test1"

shouldTruefunction is implemented using lihaoyi`s sourcecodelibrary:

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