我有一个Akka HTTP服务,它返回一个字符串,如下所示:
val route1: Route = {
path("hello") {
get{
complete{
println("Inside r1")
"You just accessed hello"
}
}
}
}
我想了解map和flatMap之间的区别
例如,下面的代码按预期给出了结果:
val future1: Future[String] =
Http()
.singleRequest(
HttpRequest(method = HttpMethods.GET,
uri = "http://localhost:8187/hello"))
.flatMap(testFlatFunc)
def testFlatFunc(x: HttpResponse): Future[String] = {
Unmarshal(x).to[String]
}
但是,如果我尝试用地图替换它,如下所示我输出为FulfilledFuture(You just accessed hello)
val future1: Future[String] = Http()
.singleRequest(
HttpRequest(method = HttpMethods.GET,
uri = "http://localhost:8187/hello"))
.map(testFunc)
def testFunc(x: HttpResponse): String={
Unmarshal(x).to[String].toString
}
为什么我的地图()无法按预期工作?
答案 0 :(得分:1)
map
和flatMap
差异:
flatMap
会折叠一级嵌套结构(它会调用fallten),例如:List(List(1), List(2)).flatMap(i => i)
将:List(1, 2)
因此,代码testFlatFunc
和testFunc
返回类型为Future[String]
,map
和flatMap
函数返回类型同样为Future[T]
,但flatMap
会使巢结构变平,因此:Future[Future[String]]
将展平为Future[String]
。并且map
函数不会这样做,所以:
val future1:Future[String] = Http()
.singleRequest(
HttpRequest(method = HttpMethods.GET,
uri = "http://localhost:8187/hello")).map(testFunc)
返回类型应为:
val future1:Future[Future[String]] = Http()
.singleRequest(
HttpRequest(method = HttpMethods.GET,
uri = "http://localhost:8187/hello")).map(testFunc)
答案 1 :(得分:1)
关于你在testFunc
中做了什么:
def testFunc(x: HttpResponse): String = {
Unmarshal(x).to[String].toString
}
这里的类型还可以,但你在里面做的不是。
Unmarshal(x).to[String]
返回Future[String]
- 这意味着它是异步结果,其值将及时出现在那里。可以在flatMap
中使用此类结果类型。
val sqrts: Double => List[Double] = x => List(Math.sqrt(x), -Math.sqrt(x))
val numbers = List(4.0, 9.0, 16.0)
numbers.flatMap(sqrts) // List(2.0, -2.0, 3.0, -3.0, 4.0, -4.0)
// results equal to
numbers
.map(sqrts) // List(List(2.0, -2.0), List(3.0, -3.0), List(4.0, -4.0))
.flatten // List(2.0, -2.0, 3.0, -3.0, 4.0, -4.0)
在这里你可以看到flatMap的工作方式就像map + flatten(除了某些容器甚至不必实现展平,例如Future
;)。
但是为什么你的testFunc
会失败?基本上你采用异步结果(Future[String]
)并且你不等待结果 - 你调用toString而只打印一些无用的信息(FulfilledFuture(You just accessed hello)
)而不是结果本身。
要解决此问题,您必须执行以下操作:
def testFunc(x: HttpResponse): String = {
Await.result(Unmarshal(x).to[String], 10.seconds)
}
这会阻塞并等待最多10秒钟,以使结果同步。 (在这种情况下,这种情况超出了目的,如果您在那里计算的结果首先是同步的,那么map
会更有用。)