Ответ 1
При столкновении с такой проблемой, когда вы хотите использовать разные типы в понимании, одним из решений может быть попытка выбрать один из типов и сопоставить другой тип с ним. Для вашей ситуации, учитывая уникальные свойства (асинхронный) фьючерсов, я бы выбрал Future
как самый низкий общий знаменатель и сопоставил Try
с 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.success
и Future.failed
влияет на то, что ExecutionContext
находится в области видимости в том, что он подчинит ему еще одну задачу под капотом.
ИЗМЕНИТЬ
Как отметил Виктор в комментариях, процесс преобразования a Try
в Future
еще проще, если вы просто используете Future.fromTry
, как в обновленном примере ниже:
val result = for{
a <- someFuture
b <- Future.fromTry(processResult(a))
} yield b
result.map { /* Success Block */ } recover { /* Failure Block */ }
Это, пожалуй, лучший выбор для вас, если вы делаете что-то с импликацией или сворачиваете свою собственную логику преобразования.