是否有更惯用的方法来重复调用map(不使用flatMap)?
请参阅以下示例:
val futureJson : Future[Seq[JsValue]] = futureBlogList.map(
blogList => blogList.map(
blog => Json.obj("id" -> blog.id, "title" -> blog.title)))
val futureResult : Future[Result] = futureJson.map(jsList => Ok(JsArray(jsList)))
这是Play中的一个函数,在这种情况下需要返回Future [Result]。
我尝试使用"进行理解"但尚未找到 flatMap 的应用程序。我使用flatMap的尝试让我看到了Future [Nothing]。
val futureJson : Future[Nothing] = for {
blogList : Seq[Blog] <- futureBlogList
blog : Blog <- blogList
} yield {
Json.obj("id" -> blog.id, "title" -> blog.title)
}
答案 0 :(得分:3)
flatMaps
的组合
和一个map
功能。Seq[...]
,Option[...]
,...)您的工作解决方案包含两个map
和一个Future
以及一个Seq
,因此无法将其转换为for comprehension(很好)。
有关理解(以及使用flatMap/map
的转换)的更多信息,请参阅Programming in Scala, 1ed和this question。
如果您真的想要使用for comprehension而不是两个map
,我们可以(作为教育练习)将第一个map
转换为flatMap
。然后,使用blogList
的函数应返回Future
:
futureBlogList.flatMap(blogList =>
Future.successful(
blogList.map(blog => Json.obj("id" -> blog.id, "title" -> blog.title))
)
)
我们可以将第二个map
转换为for表达式:
futureBlogList.flatMap(blogList =>
Future.successful(
for (blog <- blogList) yield Json.obj("id" -> blog.id, "title" -> blog.title)
)
)
//.map(identity)
我们可以将其转化为以下(非常难看)以便理解:
for {
blogList <- futureBlogList
jsonBlogs <- Future.successful(
for (blog <- blogList) yield Json.obj("id" -> blog.id, "title" -> blog.title)
)
) yield jsonBlogs
答案 1 :(得分:1)
for-comprehension 失败的原因是它可以处理相同类型的容器。在您的示例中,您将Future
与集合混合。 True ,两者都有map
但它们是不同类型的容器,因此它们的map
/ flatmap
链无法互操作,因此无法在换理解。如果您展开 for-comprehension ,您将获得
futurBlogList.flatMap { blogList =>
blogList.map { blog =>
Json.obj("id" -> blog.id, "title" -> blog.title)
}
}
flatMap
期望结果为Future[U]
,但内部的map
调用会返回Seq[JSList]
。
最终结果是,您嵌套两种不同类型的map
是表达构造的最惯用方式。最好你可以将这两个调用结合起来:
val futureResult : Future[Result] = futureBlogList.map { blogList =>
Ok(JsArray(
blogList.map( blog => Json.obj("id" -> blog.id, "title" -> blog.title))
))
}