scala 基于成功的结果失败的未来
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16695116/
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
Failing a Future based on a successful result
提问by cmbaxter
I have a scenario in my code where I need to make a Futurefail based on a successful result that contains a certain value. I can make this work just fine via flatMap, but I want to know if there is a cleaner way to make this work. First, a very simplified example:
我的代码中有一个场景,我需要Future根据包含特定值的成功结果进行失败。我可以通过 使这项工作正常进行flatMap,但我想知道是否有更简洁的方法来完成这项工作。首先,一个非常简化的例子:
import concurrent._
case class Result(successful:Boolean)
object FutureTest {
def main(args: Array[String]) {
import ExecutionContext.Implicits._
val f = Future{Result(false)}.flatMap{ result =>
result match{
case Result(false) => Promise.failed(new Exception("The call failed!!")).future
case _ => Promise.successful(result).future
}
}
f onFailure{
case x => println(x.getMessage())
}
}
}
So in my example here, I want the Futureto be failed if the Resultreturned has a value of falsefor its success indicator. As I mentioned, I can make this work okay with flatMap, but the line of code I would like to eliminate is:
因此,在我的示例中,Future如果Result返回false的成功指标值为,我希望失败。正如我提到的,我可以使用 来完成这项工作flatMap,但我想消除的代码行是:
case _ => Promise.successful(result).future
This statement seems unnecessary. The behavior that I would like is to be able to define the condition and if it evaluates to true, allow me to return a different Futureas I am doing, but if it's not true, just leave things as they are (sort of like PartialFunctionsemantics. Is there a way to do this that I'm just not seeing? I've looked at collectand transformand those don't seem to be the right fit either.
这个说法似乎没有必要。我想要的行为是能够定义条件,如果它的计算结果为真,则允许我在执行时返回一个不同的值Future,但如果它不是真的,就保持原样(有点像PartialFunction语义。有没有办法做到这一点,我只是没有看到?我看collect,并transform和那些似乎并没有成为合适人选任。
Edit
编辑
After getting the mapsuggestion from @Rex Kerr and @senia, I created a PimpedFutureand an implicit conversion to pretty up the code a bit like so:
在得到map@Rex Kerr 和@senia的建议后,我创建了PimpedFuture一个隐式转换来修饰代码,如下所示:
class PimpedFuture[T](f:Future[T])(implicit ex:ExecutionContext){
def failWhen(pf:PartialFunction[T,Throwable]):Future[T] = {
f map{
case x if (pf.isDefinedAt(x)) => throw pf(x)
case x => x
}
}
}
The implicit
隐含的
implicit def futToPimpedFut[T](fut:Future[T])(implicit ec:ExecutionContext):PimpedFuture[T] = new PimpedFuture(fut)
And the new handling code:
以及新的处理代码:
val f = Future{ Result(false) } failWhen {
case Result(false) => new Exception("The call failed!!")
}
I think this is a little cleaner while still utilizing the suggestion to use map.
我认为这更简洁,同时仍然利用建议使用map.
回答by Rex Kerr
You can do this with less effort with map:
你可以用更少的努力做到这一点map:
val f = Future{ Result(false) } map {
case Result(false) => throw new Exception("The call failed!!")
case x => x
}
but you still need to explicitly mention that you're passing the identity through.
但是您仍然需要明确提及您正在传递身份。
Note that that you should notuse andThenin such cases. andThenis for side effects, not for changing the result (unlike the Function1method of the same name).
请注意,您不应该andThen在这种情况下使用。andThen是为了副作用,而不是为了改变结果(与Function1同名方法不同)。
回答by Tal G.
There is also a different solution (without stacktrace side effect as @cmbaxter mentioned)
还有一个不同的解决方案(没有@cmbaxter 提到的堆栈跟踪副作用)
val prom = Promise[Int]()
val f = future {
1
}
f onComplete {
case Success(i) if i < 5 => prom.failure(new RuntimeException("_ < 5"))
case Success(x) => prom.success(x)
}
prom.future onComplete {
case Success(s) => println(s"We cool '$s'")
case Failure(th) => println(s"All failed, ${th.getMessage}")
}
回答by Tom Wang
The cleanest solution is to call the filtermethod, as @senia mentioned in the comments.
最干净的解决方案是调用该filter方法,正如@senia 在评论中提到的那样。
Future { Result(false) }.filter(_.successful) // throws NoSuchElementException
If you want a different exception type, you can chain the call with recoverWith:
如果你想要一个不同的异常类型,你可以用以下链接调用recoverWith:
Future { Result(false) }.filter(_.successful).recoverWith {
case _: NoSuchElementException => Future.failed(new Exception("The call failed!!"))
}

