说我有以下操作必须按顺序进行
:在代码中,它可能看起来像这样:
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
?是否可以map
和Future
产生副作用,同时自动保留原始Future
的值和严格的操作顺序?
答案 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)
magicalFlatMap
似乎是cats.FlatMap#flatTap
https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/FlatMap.scala#L150