2
我們有一個Scala/Play應用程序,其中有幾個隱式類可以根據請求創建Try對象,例如,在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生成訪問包裝的對象從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 + implicit class def組合的爆炸。理想情況下,我希望能夠以特別的方式組合多個Try對象,例如
def route(pathParam: String) = BasicAction {
request => compose(request.user, request.paging).flatMap(userWithPaging => ...)
}
,並有一個嘗試[用戶與尋呼]神奇組成的我,但我不知道我怎麼會去這樣做 - 我一直在與類型系統摔跤嘗試分配一個有意義的鍵入「撰寫」沒有任何成功。
如何將多個Try對象組合在一起,或者使用另一種語言構造來構建等價物?
...不要忘記,'未來[T]'本質上是一個'試[T]'是不是招尚未完成 - 我們決定讓所有服務級別的電話都返回期貨,這很好。你可以獲得所有這些「完美」的好處,再加上它與Play的異步支持相得益彰。即使一個特定的服務並不需要異步,將結果包裝在Future.successful()中也是如此簡單,你也可以! :-) – millhouse