scala – 我的API都是返回Future [Option [T]],如何在comp-compr
我的所有API方法返回Future [Option [T]],试图找出如何优雅地执行以下操作:
case class UserProfile(user: User,location: Location,addresses: Address) 以下代码目前无法编译,因为用户,位置和地址都是Option [User],Option [Location]和Option [Address] val up = for { user <- userService.getById(userId) location <- locationService.getById(locationId) address <- addressService.getById(addressId) } yield UserProfile(user,location,address) 我记得scalaz有OptionT,但我从来没有真正使用它,不知道如何应用于我的情况. 如果说用户,位置或地址实际返回None,那么当我需要在这种情况下将它应用到3个模型时,使用OptionT会发生什么情况? 解决方法
一些简单的定义为了一个完整的工作示例:
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future type User = String type Location = String type Address = String case class UserProfile(user: User,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,address) ) 即我们必须嵌套理解,就像我们必须嵌套地图来转换例如.可能在Future [Option [Int]]内部的Int值. Scalaz或Cats中的OptionT单变量变换器旨在允许您使用类似于Future [Option [A]]的类型,而无需嵌套.例如你可以写这个: import scalaz.OptionT,scalaz.std.scalaFuture._ def getProfile(uid: Long,aid: Long): OptionT[Future,UserProfile] = for { user <- OptionT(getUserById(uid)) location <- OptionT(getLocationById(lid)) address <- OptionT(getAddressById(aid)) } yield UserProfile(user,address) 或者如果你想要一个Future [Option [UserProfile]],你可以调用run: def getProfile(uid: Long,aid: Long): Future[Option[UserProfile]] = ( for { user <- OptionT(getUserById(uid)) location <- OptionT(getLocationById(lid)) address <- OptionT(getAddressById(aid)) } yield UserProfile(user,address) ).run 接着: scala> getProfile(1L,1L,1L).foreach(println) Some(UserProfile(Foo McBar,The Moon,123 Moon St.)) 如果任何中间结果为无,整个事情将为无: scala> getProfile(1L,0L).foreach(println) None scala> getProfile(0L,0L,0L).foreach(println) None 当然,如果任何一个请求失败,整个事情就会失败,出现第一个错误. 作为脚注,如果请求不依赖于彼此,则可以适用而不是单一地组合它们: import scalaz.Scalaz._ def getProfile(uid: Long,aid: Long): Future[Option[UserProfile]] = ( OptionT(getUserById(uid)) |@| OptionT(getLocationById(lid)) |@| OptionT(getAddressById(aid)) )(UserProfile.apply _).run 这可以更精确地对计算进行建模,并且可能会更有效率,因为它可以并行运行请求. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |