onSuccess и onFailure ничего не возвращают, когда они являются последним оператором в def - PullRequest
0 голосов
/ 16 апреля 2019

Я пытаюсь работать с коллекцией фьючерсов, и у меня возникают проблемы с возвратом результата из определения, основанного на будущем статусе. Ниже мой код:

final case class StagesToRun(stages : Set[StageRun])
private def processNextStagesAndAccumulateResults(stagesToRun: StagesToRun): \/[Exception, Success] = {
val stageProcessingExceptions = mutable.Set[Exception]()
//processor.process(stagesToRun) => returns a Set[Future[\/[Exception, Success]]] and I am converting it to  Future[Set[\/[Exception, Success]]] in below expression
val processResults = Future.sequence(processor.process(stagesToRun))
processResults.onSuccess {
  case result => {
    result.map { res =>
      res.fold(
        l => stageProcessingExceptions += l,
        r => r
      )
    }
    if (stageProcessingExceptions.isEmpty) Success.right
    else new Exception("Got exception while processing one of the stage").left
  }
}
processResults.onFailure {
  case ex =>  new Exception(ex.getMessage)).left
}
}

Теперь, согласно соглашениям Scala, последний оператор моей функции становится оператором возврата моей функции. В этой функции это должен быть в основном результат if (stageProcessingExceptions.isEmpty) Success и соответствующий ему else или результат onFailure, т. Е. new Exception(ex.getMessage)). Однако компилятор продолжает говорить мне, что возвращаемый тип является единицей, а не ожидаемой дизъюнкцией. Может кто-нибудь, пожалуйста, помогите мне здесь? Спасибо

Ответы [ 2 ]

5 голосов
/ 16 апреля 2019

Вы абсолютно правы, когда говорите, что последний оператор функции становится оператором возврата. Однако, если вы видите определение метода onSuccess и onFailure, они оба возвращают Unit в качестве возвращаемого типа.

Из документов Scala подпись onSuccess -

def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit = onComplete {
    case Success(v) =>
      pf.applyOrElse[T, Any](v, Predef.identity[T]) // Exploiting the cached function to avoid MatchError
    case _ =>
  }

В похожих строках onFailure возвращает единицу.

 def onFailure[U](@deprecatedName('callback) pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = onComplete {
    case Failure(t) =>
      pf.applyOrElse[Throwable, Any](t, Predef.identity[Throwable]) // Exploiting the cached function to avoid MatchError
    case _ =>
  }

В вашей ситуации вы можете применить к карте функцию на будущее, а не onComplete. Это поможет вам распространять ваш требуемый тип. Кроме того, если вы хотите обработать условие, когда ваше будущее терпит неудачу, вы можете добавить блок восстановления к своему будущему как

 .recover {
          case _ =>
         //whatever type you want to propogate ex: Left()
        }
3 голосов
/ 16 апреля 2019

Оба onSuccess и onFailure возвращают Unit и предназначены для реализации побочных эффектов. Если вы хотите вернуть измененный Future, используйте transform. Одна версия этого принимает две функции: первая функция обрабатывает успешные результаты, а вторая обрабатывает исключения.

processResults.transform(
  { result =>
    // process result and return new result
    // throw error on failure
    result
  },
  { ex =>
    // Process exception and return new exception
    ex
  }
)

Если вы выбросите исключение в любую функцию, вы получите ошибку Future.

Существует еще одна версия transform, которая принимает функцию Try => Try, которая позволяет превратить ошибку Future в успех Future, которая невозможна в указанной выше версии.

...