Scala 我的API全部返回Future[Option[T]],如何在for compr中很好地组合它们
我的所有API方法都返回Future[Option[T]],试图找出如何优雅地执行以下操作:Scala 我的API全部返回Future[Option[T]],如何在for compr中很好地组合它们,scala,scalaz,Scala,Scalaz,我的所有API方法都返回Future[Option[T]],试图找出如何优雅地执行以下操作: case class UserProfile(user: User, location: Location, addresses: Address) 以下代码当前未编译,因为用户、位置和地址都是选项[user]、选项[location]和选项[address] val up = for { user <- userService.getById(userId) location <-
case class UserProfile(user: User, location: Location, addresses: Address)
以下代码当前未编译,因为用户、位置和地址都是选项[user]、选项[location]和选项[address]
val up = for {
user <- userService.getById(userId)
location <- locationService.getById(locationId)
address <- addressService.getById(addressId)
} yield UserProfile(user, location, address)
val up=for{
用户为了完整的工作示例,需要一些简单的定义:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
type User = String
type Location = String
type Address = String
case class UserProfile(user: User, location: Location, addresses: Address)
def getUserById(id: Long): Future[Option[User]] = id match {
case 1 => Future.successful(Some("Foo McBar"))
case _ => Future.successful(None)
}
def getLocationById(id: Long): Future[Option[Location]] = id match {
case 1 => Future.successful(Some("The Moon"))
case _ => Future.successful(None)
}
def getAddressById(id: Long): Future[Option[Address]] = id match {
case 1 => Future.successful(Some("123 Moon St."))
case _ => Future.successful(None)
}
为了完整起见,下面是无Scalaz的实现:
def getProfile(uid: Long, lid: Long, aid: Long): Future[Option[UserProfile]] =
for {
maybeUser <- getUserById(uid)
maybeLocation <- getLocationById(lid)
maybeAddress <- getAddressById(aid)
} yield (
for {
user <- maybeUser
location <- maybeLocation
address <- maybeAddress
} yield UserProfile(user, location, address)
)
或者,如果您想要一个未来[选项[UserProfile]]
您可以调用run
:
def getProfile(uid: Long, lid: Long, aid: Long): Future[Option[UserProfile]] = (
for {
user <- OptionT(getUserById(uid))
location <- OptionT(getLocationById(lid))
address <- OptionT(getAddressById(aid))
} yield UserProfile(user, location, address)
).run
如果任何中间结果为None
,则整个结果将为None
:
scala> getProfile(1L, 1L, 0L).foreach(println)
None
scala> getProfile(0L, 0L, 0L).foreach(println)
None
当然,如果任何一个请求失败,整个过程都会失败,出现第一个错误
作为一个脚注,如果请求彼此不依赖,您可以应用程序而不是一元编写它们:
import scalaz.Scalaz._
def getProfile(uid: Long, lid: Long, aid: Long): Future[Option[UserProfile]] = (
OptionT(getUserById(uid)) |@|
OptionT(getLocationById(lid)) |@|
OptionT(getAddressById(aid))
)(UserProfile.apply _).run
这可以更准确地模拟计算,而且可能更高效,因为它可以并行运行请求。这就是我所说的全自动运行人,谢谢!|@|就像未来一样。顺序?@Blankman是的,最大的区别是它可以处理不同的类型(同时保持类型和算术).FYI:Future.onSuccess
已被弃用,因为Scala 2.12@TravisBrown我实际上需要添加另一个调用,但它返回一个Future[Seq[T]]。鉴于上述情况,现在可以添加这个吗?@n4to4更新为使用foreach
。因为这是关于option
的明确说明,也许它应该有一个scalaz
标签(也可能是monad变压器
和/或scala猫
)?
scala> getProfile(1L, 1L, 0L).foreach(println)
None
scala> getProfile(0L, 0L, 0L).foreach(println)
None
import scalaz.Scalaz._
def getProfile(uid: Long, lid: Long, aid: Long): Future[Option[UserProfile]] = (
OptionT(getUserById(uid)) |@|
OptionT(getLocationById(lid)) |@|
OptionT(getAddressById(aid))
)(UserProfile.apply _).run