scala 等待未来,得到一个
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21417317/
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
Await a future, receive an either
提问by schmmd
I'd like to await a scala future that may have failed. If I use Await.resultthe exception will be thrown. Instead, if I have f: Future[String]I would like a method Await.resultOpt(f): Option[String]or Await.resultEither(f): Either[String].
我想等待一个可能失败的 Scala 未来。如果我使用Await.result该异常将被抛出。相反,如果我有f: Future[String]我想要一种方法Await.resultOpt(f): Option[String]或Await.resultEither(f): Either[String].
I could get this by using scala.util.control.Exception.catchingor I could f map (Right(_)) recover { case t: Throwable => Left(t) }, but there must be a more straightforward way.
我可以通过使用scala.util.control.Exception.catching或我可以得到这个f map (Right(_)) recover { case t: Throwable => Left(t) },但必须有一个更直接的方法。
回答by Dylan
You could use Await.readywhich simply blocks until the Future has either succeeded or failed, then returns a reference back to that Future.
您可以使用Await.readywhich 简单地阻塞直到 Future 成功或失败,然后返回对该 Future 的引用。
From there, you would probably want to get the Future's value, which is an Option[Try[T]]. Due to the Await.readycall, it should be safe to assume that the valueis a Some. Then it's just a matter of mapping between a Try[T]and an Either[Throwable, T].
从那里,你可能会想未来的value,这是一个Option[Try[T]]。由于Await.ready调用,可以安全地假设value是Some。那么这只是 aTry[T]和 an之间的映射问题Either[Throwable, T]。
The short version:
简短版本:
val f: Future[T] = ...
val result: Try[T] = Await.ready(f, Duration.Inf).value.get
val resultEither = result match {
case Success(t) => Right(t)
case Failure(e) => Left(e)
}
回答by som-snytt
The shorter version, just to promote the API:
较短的版本,只是为了推广 API:
scala> val f = Future(7)
f: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@13965637
scala> f.value.get
res0: scala.util.Try[Int] = Success(7)
scala> import scala.util._
import scala.util._
scala> Either.cond(res0.isSuccess, res0.get, res0.failed.get)
res2: scala.util.Either[Throwable,Int] = Right(7)
scala> val f = Future[Int](???)
f: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@64c4c1
scala> val v = f.value.get
v: scala.util.Try[Int] = Failure(java.util.concurrent.ExecutionException: Boxed Error)
scala> Either.cond(v.isSuccess, v.get, v.failed.get)
res4: scala.util.Either[Throwable,Int] = Left(java.util.concurrent.ExecutionException: Boxed Error)
It has a slight advantage in being a one-liner.
作为单线,它有一点优势。
But of course, after adding a .toEitherextension method, you don't care how many lines it took.
但是当然,添加了.toEither扩展方法之后,你就不用在意花了多少行了。
回答by Rhys Bradbury
You could start to make your own type utils and do something like so
您可以开始制作自己的类型工具并执行类似的操作
trait RichTypes {
import scala.util.{Try, Success, Failure}
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
implicit class RichFuture[T](f: Future[T]) {
def awaitResult(d: Duration): Either[Throwable, T] = {
Try(Await.result(f, d)).toEither
}
}
implicit class RichTry[T](tri: Try[T]) {
def toEither(): Either[Throwable, T] = {
tri.fold[Either[Throwable, T]](Left(_), Right(_))
}
}
}
object Example
extends App
with RichTypes {
import scala.concurrent.Future
import scala.concurrent.duration._
val succ = Future.successful("hi").awaitResult(5.seconds)
val fail = Future.failed(new Exception("x")).awaitResult(5.seconds)
println(succ) // Right(hi)
println(fail) // Left(Exception(x))
}
I separated it out for a Tryto also have a .fold:).
我把它分开了一个Try也有一个.fold:)。

