对Future的价值执行操作,以解决其副作用,丢弃结果并保留原始值,但保留操作顺序

时间:2019-06-24 21:53:51

标签: scala future scala-cats

说我有以下操作必须按顺序进行

  1. 获取博客帖子
  2. 发布分析
  3. 转发博客文章

在代码中,它可能看起来像这样:

val blogPostFut: Future[BlogPost] = blogService.getPost(postId)
val afterAnalytics: Future[BlogPost] = blogPostFut.flatMap(blogPost =>
  val ignoredResponse: Future[Analytics] = analyticsService.sendAnalytics(blogPost)
  ignoredResponse.map(_ => blogPost)  // <-- THIS BOTHERS ME
)
val finalValue: Future[ForwardResult] = afterAnalytics.flatMap(blogPost =>
  forwardService.forward(blogPost)
)

为了确保执行的正确顺序,我感到不安,我必须在blogPost中转发ignoredResponse,以确保它可用于步骤3。

如果可以做这样的事情,我会很乐意的:

blogPostFut.magicalFlatMap(analyticsService.sendAnalytics)

magicalFlatMap的实现方式如下:

// pseudocode
def magicalFlatMap[A,B](f: A => Future[B]): Future[A] = f().map(_ => this.value)

Scala stdlib或Cats中是否存在magicalFlatMap?是否可以mapFuture产生副作用,同时自动保留原始Future的值和严格的操作顺序?

2 个答案:

答案 0 :(得分:2)

尝试Future.andThen的副作用

for {
  blogPost <- blogService.getPost(postId).andThen { case Success(post) => analyticsService.sendAnalytics(post) }
  finalValue <- forwardService.forward(blogPost)
} yield {
  finalValue
}

这是一个虚拟的例子

  val result = for {
    v1 <- Future(1)
    v2 <- Future(v1 + 2).andThen { case  Success(v) => println(v) }
    v3 <- Future(v1 + v2)
  } yield {
    v3
  }

  result.foreach(println)

应输出

3
4

我们也可以做

for {
  blogPost   <- blogService.getPost(postId) 
  _          <- analyticsService.sendAnalytics(blogPost)
  finalValue <- forwardService.forward(blogPost)
} yield {
  finalValue
}

然而,在这种情况下,analyticsService.sendAnalytics(blogPost)中的失败会使整个理解能力短路,这可能是不希望的。

答案 1 :(得分:2)