Scala Future: трансформировать будущее [вектор [T]] в будущее [результат] - PullRequest
2 голосов
/ 11 июня 2019

У меня есть метод, который создает Future типа Vector, из которого я затем хочу создать соответствующий ответ HTTP.

Я пытался реализовать это до сих пор, используя transform иМетоды transformWith из Futures API в основном потому, что они имеют сигнатуру Try[T] для своих аргументов, и я могу различить успех и неудачу.

Предположим, что это метод, производящий Future типа Vector

def aCoupleOfFutures: Future[Vector[String]] = ???

Используя этот подход, можно заметить повторное использование Try структуры

val foo:Future[Result] = aCoupleOfFutures.transform {
    case Success(strings) => Try(Created(json.Json.toJson(strings)))
    case Failure(e) => Try(BadRequest(e.getMessage))
}

Используя этот подход, можно заметить повторное использование Future.successful вложенности.

val foo:Future[Result] = aCoupleOfFutures.transformWith {
    case Success(strings) => Future.successful(Created(json.Json.toJson(strings)))
    case Failure(e) => Future.successful(BadRequest(e.getMessage))
}

Используя этот подход, я не могу вернуть необходимое BadRequest, когда из службы возникла исключительная ситуация.Поскольку подпись перегруженного transform метода - (def transform[S](s: T => S, f: Throwable => Throwable))

val foo:Future[Result] = aCoupleOfFutures.transform (
    options => Created(json.Json.toJson(options)),
    exc => exc
)

Итак, мой вопрос: могу ли я иметь что-то вроде следующего:

val result:Future[Result] = aCoupleOfFutures. someKindOfTransform {
    case Success(options) => Created(json.Json.toJson(options))
    case Failure(e) => BadRequest(e.getMessage)
}

Ответы [ 2 ]

2 голосов
/ 11 июня 2019

Кажется, что самый простой вариант - разделить его на map и recover шаги:

val result = aCoupleOfFutures
  .map(options => Created(json.Json.toJson(options)))
  .recover{ case exc => BadRequest(exc.getMessage)}

Вы правы, что, похоже, не существует ни одного метода преобразования, выполняющего то, что выwant - ближайшая сигнатура кажется onComplete, но она возвращает Unit и поэтому не позволяет получить возвращаемое значение.Тем не менее, разделение между ними не обязательно является плохой вещью, так как вам часто нужно абстрагировать логику обработки ошибок на всех ваших контроллерах.

1 голос
/ 16 июня 2019

Здесь будет полезна операция сгиба -

def fold[U](fa: Throwable => U, fb: T => U): U

Это терминальная операция, вы хотите преобразовать все результаты или исключения в Result.Операция свертывания над опцией try / any / преобразует всю вещь в любом состоянии в тип U.

val result = aCoupleOfFutures
  .transform(
    tryResult =>
      Success(
        tryResult.fold(th => BadRequest(th.getMessage), options => Created(json.Json.toJson(options)))
      )
  )
...