Ожидайте будущего, получите либо
Я хотел бы ожидать будущего 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) }
, но должен быть более простой способ.
Ответы
Ответ 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
вам все равно, сколько строк потребовалось.