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

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

Await a future, receive an either

scalafuture

提问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调用,可以安全地假设valueSome。那么这只是 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:)。