scala - 如何使用包装了 Either 的 Future?
问题描述
在我当前的项目中,我使用Either[Result, HandbookModule]
( Result
is 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]]
a Either[A, Future[B]]
?
解决方案
为了从 Future 中解开您的方法,您必须阻止它并等待结果。您可以使用Await.result
.
但是阻止未来通常不被认为是最佳实践。更多关于这个here。
所以你应该以不同的方式解决这个问题。您面临的实际上是嵌套 monad 堆栈的常见问题,并且可以使用 monad 转换器处理。
Scala 的函数式编程库cat提供了EitherT monad 转换器的实现。
在您的情况下,您可以使用EitherT.apply
to transform Future[Either[Result, List[Module]]
intoEitherT[Future, Result, List[Module]]
和EitherT.fromEither
to lift 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
}
推荐阅读
- reactjs - TypeError:无法读取未定义 React 的属性“状态”,传递给其他组件的状态未定义
- flutter - 如何开发不同的屏幕尺寸?
- go - http.ServeFile () - 客户端上的文件名问题
- python - 为什么这个字符串不会转换为浮点数?
- testing - 如何计算执行时间开销
- dictionary - 在 Golang 中将命名类型 map[string]string 转换为普通类型
- javascript - 量角器茉莉花在错误/预期失败时捕获异常
- javascript - 从 Mongoose 的数组中删除一个对象
- python - 如何仅绘制具有某些数组值的单元格,而其他不使用 matplotlib.pyplot 的单元格?
- html - 为什么容器内的 div 元素默认不占用 12 列而只占用 1 列?