这是对 Abhijit Sarkar 对 JoeK 的回答的评论的回答,评论太大了。
首先我同意乔的观点,你试图使用collectRight 是非常可疑的。看起来您真正需要的是getOrElse 或getOrElseF。例如,这似乎与您评论中描述的行为相匹配
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
case class Event(val a: Int)
val eGood: EitherT[Future, String, Event] = EitherT[Future, String, Event](Future(Right(Event(42))))
val resultGood: Future[Event] = eGood.getOrElseF(Future.failed(new NoSuchElementException("whatever")))
val eBad: EitherT[Future, String, Event] = EitherT[Future, String, Event](Future(Left("hello")))
val resultBad: Future[Event] = eBad.getOrElseF(Future.failed(new NoSuchElementException("whatever")))
println("good = " + scala.concurrent.Await.result(resultGood, 1 second))
println()
scala.concurrent.Await.result(resultBad, 1 second)) // don't need println as there will be exception anyway
打印
好 = 事件 (42)
线程“主”java.util.NoSuchElementException 中的异常:随便
在 sg.cats.CatsMain$.$anonfun$resultBad$1(CatsMain.scala:32))
在 ...
请注意,Future.failed(new NoSuchElementException("whatever")) 实际上是 Alternative[Future] 应该具有的 empty 实现。这是没有适合所有场景的解决方案的地方之一。不过,如果您太无聊而无法一直输入,并且遇到与所有案例匹配的相同失败,您可以创建隐式操作,例如:
final class MyEitherFutureOps[A, B](val eab: EitherT[Future, A, B]) extends AnyVal {
import cats.instances.future._
def rightOrFailure(implicit ec: ExecutionContext): Future[B] = eab.getOrElseF(Future.failed(new NoSuchElementException("whatever")))
}
object MyEitherFutureOps {
implicit def ops[A, B](eab: EitherT[Future, A, B]): MyEitherFutureOps[A, B] = new MyEitherFutureOps[A, B](eab)
}
然后你可以把它当作
import MyEitherFutureOps._
val eGood: EitherT[Future, String, Event] = EitherT[Future, String, Event](Future(Right(Event(42))))
val resultGood: Future[Event] = eGood.rightOrFailure
val eBad: EitherT[Future, String, Event] = EitherT[Future, String, Event](Future(Left("hello")))
val resultBad: Future[Event] = eBad.rightOrFailure
效果与上例相同。