Scala - 链接期货尝试块?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17907772/
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
Scala - Chaining Futures Try blocks?
提问by James Davies
Is it possible to chain scala.util.Try and scala.concurrent.Future? They both effectively provide the same monadic interface, but attempting to chain them results in a compile error.
是否可以链接 scala.util.Try 和 scala.concurrent.Future?它们都有效地提供了相同的 monadic 接口,但尝试链接它们会导致编译错误。
For example. Given the two signatures below
例如。鉴于以下两个签名
def someFuture:Future[String] = ???
def processResult(value:String):Try[String] = ???
is it possible to do something like the following?
是否可以执行以下操作?
val result = for( a <- someFuture; b <- processResult( a ) ) yield b;
result.map { /* Success Block */ } recover { /* Failure Block */ }
This obviously results in a compile error, because Future and Try are unable to be flatMapp'ed together.
这显然会导致编译错误,因为 Future 和 Try 无法被 flatMapp'ed 在一起。
It would however be a nice feature to be able to chain them - is this at all possible? Or do I need to combine them into a Future[Try[String]]?
然而,能够链接它们将是一个很好的功能 - 这可能吗?或者我需要将它们组合成一个 Future[Try[String]] 吗?
(In particular, I'm interested in having a single 'recover' block to catch exceptions in either the future orthe try).
(特别是,我有兴趣在未来或尝试中使用单个“恢复”块来捕获异常)。
回答by cmbaxter
When faced with a problem like this, where you want to use differing types in a for comprehension, one solution can be to try and select one of the types and map the other type to it. For your situation, given the unique properties (async) of futures, I would select Futureas the lowest common denominator and map the Tryto the Future. You can simply do that like this:
当遇到这样的问题时,您想在理解中使用不同的类型,一种解决方案是尝试选择其中一种类型并将另一种类型映射到它。对于您的情况,鉴于期货的独特属性(异步),我将选择Future作为最低公分母并将 映射Try到Future. 你可以简单地这样做:
val result = for{
a <- someFuture
b <- tryToFuture(processResult(a))
} yield b
result.map { /* Success Block */ } recover { /* Failure Block */ }
def tryToFuture[T](t:Try[T]):Future[T] = {
t match{
case Success(s) => Future.successful(s)
case Failure(ex) => Future.failed(ex)
}
}
Now if you found this to be a very common situation and you did not like constantly having to add in the explicit conversion, I suppose you could define the tryToFuturemethod as implicit on some helper object and import it where needed like this:
现在,如果您发现这是一种非常常见的情况,并且您不喜欢不断添加显式转换,我想您可以将tryToFuture方法定义为隐式的某个辅助对象,并在需要时像这样导入它:
object FutureHelpers{
implicit def tryToFuture[T](t:Try[T]):Future[T] = {
t match{
case Success(s) => Future.successful(s)
case Failure(ex) => Future.failed(ex)
}
}
}
import FutureHelpers._
val result = for{
a <- someFuture
b <- processResult(a)
} yield b
result.map { /* Success Block */ } recover { /* Failure Block */ }
Just remember that calling Future.successand Future.failedhas an impact on whatever ExecutionContextis in scope in that it will submit another task to it under the hood.
请记住,调用Future.success和Future.failed会对ExecutionContext范围内的任何内容产生影响,因为它会在幕后向它提交另一个任务。
EDIT
编辑
As Viktor pointed out in the comments, the process of converting a Tryto aFutureis even easier if you just use Future.fromTrylike in the updated example from below:
正如 Viktor 在评论中指出的那样,如果您只是在下面的更新示例中使用like,则将Trya转换为 a 的Future过程会更容易Future.fromTry:
val result = for{
a <- someFuture
b <- Future.fromTry(processResult(a))
} yield b
result.map { /* Success Block */ } recover { /* Failure Block */ }
This is probably your best bet versus doing stuff with implicits or rolling your own conversion logic.
与使用隐式或滚动您自己的转换逻辑相比,这可能是您最好的选择。
回答by derek
How about
怎么样
val result = for( a <- someFuture) yield for( b <- processResult( a ) ) yield b;
Although it does not look neat.
虽然看起来不整齐。
回答by Carlos Fau
Perhaps the problem is old but currently you can:
也许问题很老,但目前您可以:
implicit def tryToFuture[T](t:Try[T]):Future[T] = Promise.fromTry(t).future
回答by Sofia
There is also
还有
Future.fromTry(Try { ... })
So you could do
所以你可以这样做
val result = for {
a <- someFuture
b <- Future.fromTry(processResult(a))
} yield b;
回答by chenhry
implicit def convFuture[T](ft: Future[Try[T]]): Future[T] =
ft.flatMap {
_ match {
case Success(s) => Future.successful(s)
case Failure(f) => Future.failed(f)
}
}

