Элегантная обработка Scala Future[Either]]

У меня есть тип, форма которого такова:

val myType: Future[Either[MyError, TypeA]] = // some value

Я знаю, что могу сопоставить шаблон с этим и перейти к типу Right или Left, но проблема в том, что мне придется вкладывать свою логику сопоставления с шаблоном. Я ищу гораздо более элегантный способ справиться с этим? Какие-либо предложения?

2 ответа

Решение

Если вы кодируете MyError как исключение, вам не нужно Either больше и может просто patternMatch против завершения, или использовать recoverWith чтобы сопоставить его с другим типом:

myType.onComplete {
  case Success(t) =>
  case Failure(e) =>
}

Чтобы сопоставить ваши существующие Either типы вы могли бы сделать что-то вроде этого:

case class MyException(e: MyError) extends Exception

def eitherToException[A](f: Future[Either[MyError,A]]): Future[A] = {
  f.flatMap {
    case Left(e) => Future.failed(MyException(e))
    case Right(x) => Future.successful(x)
  }
}

val myType2 = eitherToException(myType)

В качестве альтернативы, если MyError а также TypeA под вашим контролем, вы можете создать общий супер тип и сопоставление с шаблоном:

sealed trait MyResult
final case class MyError() extends MyResult
final case class TypeA() extends MyResult

myType.map {
  case MyError() => ...
  case TypeA() => ...
}

Вы можете создавать собственные объекты экстрактора:

object FullSuccess {
  def unapply[T](x: Try[Either[MyError, T]]) = x match {
    case Success(Right(x)) => Some(x)
    case _ => None
  }
}

object PartSuccess {
  def unapply[T](x: Try[Either[MyError, T]]) = x match {
    case Success(Left(err)) => Some(err)
    case _ => None
  }
}

А также

val myType: Future[Either[MyError, TypeA]] = // some value

myType.onComplete {
  case FullSuccess(x) => ... // equivalent to case Success(Right(x))
  case PartSuccess(x) => ... // equivalent to case Success(Left(x))
  case Failure(e) => ...
}
Другие вопросы по тегам