【发布时间】: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