我正在尝试使用函数异步调用3个单独的API并将响应整理到UserDetails
对象中,并将其作为函数的一部分返回。
但是,我遇到的问题是,当我将返回类型显式设置为Future[UserDetails]
时,它不会编译,因为yield
的返回不是UserDetails
对象而我我不知道如何从这里得到我想要的东西。
注意我希望返回Future[UserDetails]
,但推断的返回类型为Future[Object]
我的代码目前如下:
def getUserDetails(userId: String) = {
usersConnector.getUserById(userId).map {
case Some(user) =>
for {
connections <- connectionsConnector.getAllConnections(user.username) recover {case _ => None}
pendingConnections <- connectionsConnector.getAllPendingConnections(user.username) recover {case _ => None}
userLocation <- userLocationsConnector.getLocationByUsername(user.username) recover {case _ => None}
} yield {
UserDetails(Some(user), connections, pendingConnections, userLocation)
}
case None => UserDetails(None, None, None, None)
}
}
答案 0 :(得分:4)
问题是map函数中的情况不会返回相同的类型。
None
案例会返回UserDetails
。但是,Some
案例会返回Future[UserDetails]
。这两种类型的最小上限(最不共同的祖先)是AnyRef
,即Object
。因此,map
函数会将Future[Option[User]]
转换为Future[Object]
。
有两种方法可以解决这个问题。首先是两个使用Future.successful
案例中的None
构造函数:
...
case None => Future.successful(UserDetails(None, None, None, None))
...
现在,生成的未来类型为Future[Future[UserDetails]]
。你只需要在这一点上展平它:
...
}.flatMap(x => x) // add at the end
第二种更优雅的方式是将所有内容嵌入到理解中:
def getUserDetails(userId: String) = {
def detailsFor(user: Option[User]) = user match {
case Some(user) =>
for {
connections <- connectionsConnector.getAllConnections(user.username) recover {case _ => None}
pendingConnections <- connectionsConnector.getAllPendingConnections(user.username) recover {case _ => None}
userLocation <- userLocationsConnector.getLocationByUsername(user.username) recover {case _ => None}
} yield {
UserDetails(Some(user), connections, pendingConnections, userLocation)
}
case None => Promise.successful(UserDetails(None, None, None, None))
}
for {
user <- usersConnector.getUserById(userId)
userDetails <- detailsFor(user)
} yield userDetails
}
编辑:
请参阅下面的Łukasz关于在for-comprehension中异步启动期货的评论。