繁体   English   中英

斯卡拉 - 链接期货尝试块?

[英]Scala - Chaining Futures Try blocks?

是否可以链接scala.util.Try和scala.concurrent.Future? 它们都有效地提供相同的monadic接口,但是尝试链接它们会导致编译错误。

例如。 鉴于下面的两个签名

def someFuture:Future[String] = ???
def processResult(value:String):Try[String] = ???

可以做以下的事情吗?

val result = for( a <- someFuture; b <- processResult( a ) ) yield b;
result.map { /* Success Block */ } recover { /* Failure Block */ }

这显然会导致编译错误,因为Future和Try无法一起进行flatMapp。

然而,能够链接它们是一个很好的功能 - 这是否可能? 或者我是否需要将它们组合成一个Future [Try [String]]?

(特别是,我有兴趣使用单个'recover'块来捕获未来 try中的异常)。

当遇到这样的问题时,你想要在理解中使用不同的类型,一种解决方案可以尝试选择其中一种类型并将另一种类型映射到它。 根据您的情况,考虑到期货的独特属性(异步),我会选择Future作为最小公分母并将Try to the 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)
  }
}

现在,如果您发现这是一个非常常见的情况,并且您不喜欢不断添加显式转换,我想您可以将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 */ }

请记住,调用Future.successFuture.failed会影响ExecutionContext的范围,因为它会在Future.failed提交另一个任务。

编辑

正如Viktor在评论中所指出的那样,如果你只是使用Future.fromTry中的,将Try转换为Future将更容易,如下面的更新示例:

val result = for{
  a <- someFuture
  b <- Future.fromTry(processResult(a)) 
}  yield b
result.map { /* Success Block */ } recover { /* Failure Block */ }

这可能是您最好的选择,而不是使用implicits或滚动您自己的转换逻辑。

怎么样

val result = for( a <- someFuture) yield for( b <- processResult( a ) ) yield b;

虽然它看起来不整洁。

也许这个问题很老但是目前你可以:

  implicit def tryToFuture[T](t:Try[T]):Future[T] = Promise.fromTry(t).future
  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)
  }
}

还有

Future.fromTry(Try { ... })

所以你可以做到

 val result = for {
   a <- someFuture
   b <- Future.fromTry(processResult(a)) 
 } yield b;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM