简体   繁体   English

将EitherT[Future, A, B] 转换为Option[B]

[英]Convert EitherT[Future, A, B] to Option[B]

I have a method我有一个方法

def getInfoFromService(reqParams: Map[String, String]): Future[Either[CustomException, A]] 

and I have another function我还有另一个功能

import cats.implicits._
def processInfoAndModelResponse(input: Future[Either[CustomException, A]]): Option[A] = {
    for {
         either <- input
         resultA <- either
     } yield resultA.some
}

So basically, I am trying to convert Future[Either[CustomException, A]]) to Option[A] .所以基本上,我试图将Future[Either[CustomException, A]])Option[A] The resultA <- either in above code would not work as map is not happy with type. resultA <- either在上面的代码中都不起作用,因为地图对类型不满意。

What you try to do is basically something like你尝试做的基本上是这样的

def convert[A](future: Future[Either[CustomException, A]]): Option[A] =
  Try(Await.result(future, timeout)).toEither.flatten.toOption

This:这个:

  • looses information about error, which prevents any debugging (though you could log after .flatten )丢失有关错误的信息,这会阻止任何调试(尽管您可以在.flatten之后.flatten
  • blocks async operation which kills any benefit of using Future in the first place阻止异步操作,这首先会扼杀使用Future任何好处

Monads do not work like that. Monad 不会那样工作。 Basically you can handle several monadic calculations with for for the same monad, but Future and Either are different monads.基本上,您可以使用for为同一个 monad 处理多个 monadic 计算,但是FutureEither是不同的 monad。

Try尝试

import scala.concurrent.{Await, Future}
import scala.concurrent.duration._

def processInfoAndModelResponse(input: Future[Either[CustomException, A]]): Option[A] = {
  Await.result(input, 1.minute).toOption
}

@MateuszKubuszok 's answer is different in that it doesn't throw. @MateuszKubuszok的答案不同,因为它不会抛出。

You can't sensibly convert a Future[Either[CustomException, A]] to Option[A] , as you don't know what the result will be until the Future has completed.您不能明智地将Future[Either[CustomException, A]]Option[A] ,因为在 Future 完成之前您不知道结果会是什么。

Future[Either[CustomException, A]] might just bet kept that way, or put in IO as IO[Either[CustomException, A]] . Future[Either[CustomException, A]]可能只是打赌保持这种方式,或者将 IO 作为IO[Either[CustomException, A]] If you don't care about CustomException , you can also capture it Future (or IO ) error handling mechanisms, or just discard it entirely.如果您不关心CustomException ,您也可以捕获它Future (或IO )错误处理机制,或者完全丢弃它。

Some options:一些选项:

absorb the CustomException in Future's error handling:在 Future 的错误处理中吸收 CustomException:

val fa: Future[A] = fut.transform(_.map(_.toTry))

ignore the CustomException an make the Future return with None忽略 CustomException 并使 Future 返回 None

val fa: Future[Option[A]] = fut.map(_.toOption)

if you really want to block a thread and wait for the result,如果你真的想阻塞一个线程并等待结果,

Await.result(input, Duration.Inf).toOption

but all the caveats of awaiting apply.但所有等待的警告都适用。 See the documentaion , reproduced here:请参阅此处复制的文档

WARNING: It is strongly discouraged to supply lengthy timeouts since the progress of the calling thread will be suspended—blocked—until either the Awaitable has a result or the timeout expires.警告:强烈建议不要提供过长的超时,因为调用线程的进程将被挂起——阻塞——直到 Awaitable 有结果或超时到期。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM