如何使用一个包含Either的Future?

在我当前的项目中,我使用Either[Result, HandbookModule]( Resultis an HTTP Statuscode) 作为返回类型,以便在出现问题时创建正确的状态。我现在已经将我的数据库访问重构为非阻塞。

此更改要求我的数据库访问函数的返回类型更改为Future[Either[Result, HandbookModule]].

现在我不确定如何将此函数与另一个返回Either[Result, Long].

所以为了更好地说明我的意思:

def moduleDao.getHandbooks(offset, limit): Future[Either[Result, List[Module]] = Future(Right(List(Module(1))))

def nextOffset(offset, limit, results): Either[_, Long] = Right(1)

def getHandbooks(
  offset: Long,
  limit: Long): Future[Either[Result, (List[HandbookModule], Long)]] = {
  for {
    results <- moduleDao.getHandbooks(offset, limit)
    offset  <- nextOffset(offset, limit, results)
  } yield (results, offset)
}

在更改之前,这显然没有问题,但我不知道最好的方法是什么。

或者有没有办法将 a 转换Future[Either[A, B]]为 an Either[A, Future[B]]

回答

为了从 Future 中解开你的方法,你必须阻塞它并等待结果。你可以使用Await.result.

但是阻止未来通常不被认为是最佳实践。更多关于这里。

所以你应该以不同的方式解决这个问题。您面临的实际上是嵌套 monad 堆栈的常见问题,并且可以使用 monad 转换器来处理。

Scala 的函数式编程库cats提供了一个EitherT monad 转换器的实现。

在您的情况下,您可以使用EitherT.applyto 转换Future[Either[Result, List[Module]]EitherT[Future, Result, List[Module]]EitherT.fromEither提升Either[_, Long].

它可能看起来像这样:

import cats.data.EitherT
import cats.implicits._
  
def getHandbooks(
   offset: Long,
   limit: Long
): Future[Either[String, (List[String], Long)]] = {
  val result: EitherT[Future, String, (List[String], Long)] = for {
    results <- EitherT(moduleDao.getHandbooks(offset, limit))
    offset  <- EitherT.fromEither[Future](nextOffset(offset, limit, results))
  } yield (results, offset)

  result.value //unwrap result from EitherT
}


以上是如何使用一个包含Either的Future?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>