加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 我的API都是返回Future [Option [T]],如何在comp-compr

发布时间:2020-12-16 09:20:08 所属栏目:安全 来源:网络整理
导读:我的所有API方法返回Future [Option [T]],试图找出如何优雅地执行以下操作: case class UserProfile(user: User,location: Location,addresses: Address) 以下代码目前无法编译,因为用户,位置和地址都是Option [User],Option [Location]和Option [Address]
我的所有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

这可以更精确地对计算进行建模,并且可能会更有效率,因为它可以并行运行请求.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读