преобразование Future [A] Akka в Future [Either [Exception, A]]

Есть ли в Akka (или в стандартной библиотеке Scala 2.10) метод преобразования Future[A], который может не сработать, в Future[Either[Exception,A]]? Я знаю что ты можешь писать

f.map(Right(_)).recover {
  case e:Exception => Left(e)
}

Это кажется настолько распространенной задачей, что мне интересно, не упустил ли я что-то из виду. Меня интересуют ответы на Scala 2.9 / Akka и Scala 2.10.


person Kim Stebel    schedule 05.01.2013    source источник
comment
Сочувственная предыстория на groups.google.com/d/topic/scala- sips / OVz9WSJF1HY / обсуждение и groups.google.com/ d / topic / scala-sips / VRlDgX4yFKE / обсуждение в любом случае.   -  person som-snytt    schedule 05.01.2013
comment
Я не понимаю цели этой подписи. Теперь ваше будущее может иметь Throwable как в случае Success (Left ()), так и в случае Failure ().   -  person Viktor Klang    schedule 05.01.2013
comment
@ViktorKlang: Вы можете привести тот же аргумент против Option. Теперь ваше значение может не существовать двумя способами: None и Some(null). Но на практике понятно, что мы никогда не создаем Some(null) так же, как мы не создали бы Future[Either...], который может реально потерпеть неудачу (кроме как из-за OOME или подобных вещей).   -  person Kim Stebel    schedule 05.01.2013
comment
@KimStebel Future [Either [Throwable, T]] примерно так же полезен, как Some (null)? Звучит примерно правильно   -  person Viktor Klang    schedule 05.01.2013
comment
@ViktorKlang: Ха-ха, очень забавно. Но это не Твиттер.   -  person Kim Stebel    schedule 06.01.2013


Ответы (3)


Основная причина, по которой этот метод отсутствует, заключается в том, что он не имеет хорошей семантики: статический тип Future[Either[Throwable, T]] не гарантирует, что это будущее не может потерпеть неудачу, поэтому изменение типа в целом не принесет вам многого.

Это, конечно, может иметь смысл, если вы контролируете весь код, который обрабатывает эти фьючерсы, и в этом случае тривиально добавить его самостоятельно (это название связано с тем, что я опубликовал сообщение перед первым кофе, не стесняйтесь заменить что-то получше):

implicit class FutureOps[T](val f: Future[T]) extends AnyVal {
  def lift(implicit ec: ExecutionContext): Future[Either[Throwable,T]] = {
    val p = promise[Either[Throwable,T]]()
    f.onComplete {
      case Success(s)  => p success Right(s)
      case Failure(ex) => p success Left(ex)
    }
    p.future
  }
}

Он работает очень похоже с фьючерсами Akka 2.0, поэтому я оставляю это упражнение читателю.

person Roland Kuhn    schedule 05.01.2013
comment
Что не так с моей реализацией, кроме того, что она не помещает метод в неявный класс? - person Kim Stebel; 05.01.2013
comment
Ваша реализация создает два дополнительных фьючерса, а моя - только одно, так что это просто оптимизация. - person Roland Kuhn; 05.01.2013
comment
Это альтернатива, которую я имел в виду в своем комментарии к другому ответу, но в знак уважения к лифту Роланда я написал свой после полуночи и назвал его packaged, потому что люди говорят об упаковке исключения; и я только что просмотрел старую ветку об использовании любого из двух методов и был чувствителен к любому имени, содержащему любой из них. Это очевидно простое упражнение в разработке API, которое не так уж и просто; Я надеюсь, что по этой причине он появится в сводном сообщении в блоге. - person som-snytt; 06.01.2013

Другой вариант такого преобразования (в стандартном Scala):

f.transform(tryResult => Success(tryResult.toEither))
person Mikhail Golubtsov    schedule 27.09.2018

Я не думаю, что вы все равно захотите это сделать. Документы Akka 2.0.5 показывают это для akka.dispatch.Future:

abstract def onComplete[U](func: (Either[Throwable, T]) ⇒ U): Future.this.type

Таким образом, информация о том, что будущее может потерпеть неудачу, уже встроена в поведение Future[T]. То же самое применимо и к фьючерсам Scala 2.10, где фьючерс может завершиться как Try[T], что аналогично целям Either[Exception, T].

//in scala.concurrent.Future:
abstract def onComplete[U]
  (func: (Try[T]) ⇒ U)(implicit executor: ExecutionContext): Unit
person Dylan    schedule 05.01.2013
comment
onComplete у меня не сработает, потому что мой метод должен возвращать будущее. - person Kim Stebel; 05.01.2013
comment
В том смысле, что все находится в состоянии onComplete, альтернативой сопоставлению и восстановлению является вырезание / вставка преобразования в метод расширения, но исправление ошибки до успеха. - person som-snytt; 05.01.2013
comment
Вы все еще можете вернуть будущее. Я хочу сказать, что вам не нужно выполнять преобразование из Future[A] в Future[Either[Exception, A]], поскольку оно избыточно. - person Dylan; 05.01.2013