Подтвердить что ты не робот

Ожидайте будущего, получите либо

Я хотел бы ожидать будущего scala, которое может быть неудачным. Если я использую Await.result, будет выбрано исключение. Вместо этого, если у меня есть f: Future[String], мне нужен метод Await.resultOpt(f): Option[String] или Await.resultEither(f): Either[String].

Я мог бы получить это, используя scala.util.control.Exception.catching, или я мог бы f map (Right(_)) recover { case t: Throwable => Left(t) }, но должен быть более простой способ.

4b9b3361

Ответ 1

Вы можете использовать Await.ready, который просто блокируется до тех пор, пока будущее не преуспеет или не сработает, а затем вернет ссылку на это будущее.

Оттуда вы, вероятно, захотите получить Future value, который является Option[Try[T]]. Из-за вызова Await.ready следует с уверенностью предположить, что value является Some. Тогда это просто вопрос отображения между Try[T] и Either[Throwable, T].

Краткая версия:

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)
}

Ответ 2

Более короткая версия, чтобы продвигать API:

scala> val f = Future(7)
f: scala.concurrent.Future[Int] = [email protected]

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] = [email protected]

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)

У него есть небольшое преимущество в том, чтобы быть однострочным.

Но, конечно, после добавления метода расширения .toEither вам все равно, сколько строк потребовалось.