Return Scala 中用于 yield 的特定类型
Return a specific type from for yield in Scala
我正在尝试使用一个函数异步调用 3 个单独的 API,并将响应整理到一个 UserDetails
对象中,并将 return this 作为函数的一部分。
但是,我遇到的问题是,当我将 return 类型显式设置为 Future[UserDetails]
时,它不会编译,因为 yield
中的 return 是不是 UserDetails
对象,我不知道如何 return 从中得到我想要的东西。
注意我正在寻找 return 一个 Future[UserDetails]
但推断的 return 类型是 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)
}
}
问题是您的地图函数中的案例 return 不是同一类型。
None
案例 returns UserDetails
。但是,Some
案例 return 是 Future[UserDetails]
。这两种类型的最小上界(least common ancestor)为AnyRef
,即Object
。结果,map
函数将 Future[Option[User]]
转换为 Future[Object]
.
有两种方法可以解决这个问题。首先是两个在 None
情况下使用 Future.successful
构造函数:
...
case None => Future.successful(UserDetails(None, None, None, None))
...
现在,生成的 future 的类型为 Future[Future[UserDetails]]
。此时只需要把它压平:
...
}.flatMap(x => x) // add at the end
第二种更优雅的方法是将所有内容嵌入 for-comprehension:
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 关于异步启动期货的评论。
我正在尝试使用一个函数异步调用 3 个单独的 API,并将响应整理到一个 UserDetails
对象中,并将 return this 作为函数的一部分。
但是,我遇到的问题是,当我将 return 类型显式设置为 Future[UserDetails]
时,它不会编译,因为 yield
中的 return 是不是 UserDetails
对象,我不知道如何 return 从中得到我想要的东西。
注意我正在寻找 return 一个 Future[UserDetails]
但推断的 return 类型是 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)
}
}
问题是您的地图函数中的案例 return 不是同一类型。
None
案例 returns UserDetails
。但是,Some
案例 return 是 Future[UserDetails]
。这两种类型的最小上界(least common ancestor)为AnyRef
,即Object
。结果,map
函数将 Future[Option[User]]
转换为 Future[Object]
.
有两种方法可以解决这个问题。首先是两个在 None
情况下使用 Future.successful
构造函数:
...
case None => Future.successful(UserDetails(None, None, None, None))
...
现在,生成的 future 的类型为 Future[Future[UserDetails]]
。此时只需要把它压平:
...
}.flatMap(x => x) // add at the end
第二种更优雅的方法是将所有内容嵌入 for-comprehension:
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 关于异步启动期货的评论。