Элегантная обработка 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) => ...
}