【问题标题】:Composing multiple Try objects in Scala/Play在 Scala/Play 中组合多个 Try 对象
【发布时间】:2013-12-08 20:32:08
【问题描述】:

我们有一个 Scala/Play 应用程序,其中有几个隐式类可以从请求中创建 Try 对象,例如

implicit class RequestUtils[+T](req: Request[T]) {
  def user: Try[User] = // pull the User from the Session, or throw an UnauthorizedException
  def paging: Try[Paging] = // create a Paging object, or throw an IllegalArgumentException
}

然后我们通过 flatMaps 访问被包装的对象

def route(pathParam: String) = BasicAction {
  request => 
    request.user.flatMap(user => 
      request.paging.flatMap(paging => 
        Try{ ... }
))}

最后,ActionBuilder 从 Try 生成 SimpleResult

case class BasicRequest[A](request: Request[A]) extends WrappedRequest(request)

class BasicActionBuilder extends ActionBuilder[BasicRequest] {
  def invokeBlock[A](request: Request[A], block: (BasicRequest[A]) => Future[SimpleResult]) = {
    block(BasicRequest(request))
  }
}

def BasicAction[T](block: BasicRequest[AnyContent] => Try[T]) = {
  val f: BasicRequest[AnyContent] => SimpleResult = (req: BasicRequest[AnyContent]) =>
    block(req) match {
      case Success(s) => Ok(convertToJson(s))
      case Failure(e: UnauthorizedException) => Unauthorized(e.getMessage)
      case Failure(e: Exception) => BadRequest(e.getMessage)
      case Failure(t: Throwable) => InternalServerError(e.getMessage)
    }

  val ab = new BasicActionBuilder
  ab.apply(f)
}

我们正在尝试找到一种方法,基本上将多个 Try 对象组合在一起(或类似的东西 - 我们并不热衷于使用 Trys) - flatMaps 对于一个或两个 Trys 工作正常,但嵌套它们更多这会妨碍程序的可读性。我们可以手动将对象组合在一起,例如

case class UserAndPaging(user: User, paging: Paging)

implicit class UserAndPagingUtils[+T](req: Request[T]) {
  def userAndPaging: Try[UserAndPaging] = req.user.flatMap(user => req.paging.flatMap(paging => UserAndPaging(user, paging))
}

但这会导致 case class + 隐式 class def 组合的爆炸式增长。理想情况下,我希望能够以特别的方式将多个 Try 对象组合在一起,例如

def route(pathParam: String) = BasicAction {
  request => compose(request.user, request.paging).flatMap(userWithPaging => ...)
}

并为我神奇地编写了一个 Try[User with Paging],但我不知道该怎么做 - 我一直在与类型系统搏斗,试图为“撰写”分配一个有意义的类型" 没有任何成功。

如何将多个 Try 对象组合在一起,或者使用另一种语言结构来组合一些等效对象?

【问题讨论】:

    标签: scala playframework


    【解决方案1】:

    Trys 可以是used in for-comprehensions,因为它们有一个flatMap 函数:

    def route(pathParam: String) = BasicAction { request =>
      val userWithPaging =
        for {
          user <- request.user
          paging <- request.paging
        } yield {
          doSomethingWith(user, paging)
        } 
    }
    

    【讨论】:

    • ...不要忘记Future[T] 本质上是一个尚未完成的Try[T] - 我们决定让我们所有的服务级别调用返回Futures,并且太好了。你会得到所有for-complehension 的好处,而且它与 Play 的异步支持完美契合。即使一个特定的服务真的不需要异步,也可以很容易地将结果包装在Future.successful() 中,你也可以! :-)
    猜你喜欢
    • 2013-02-09
    • 1970-01-01
    • 2017-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-24
    • 1970-01-01
    • 2022-06-10
    相关资源
    最近更新 更多