2013-11-24 3 views
2

У нас есть приложение Scala/Play, в котором у нас есть несколько неявных классов, которые создают объекты Try из запроса, например.Составление нескольких объектов Try в Scala/Play

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-неявного класса def. В идеале я хотел бы объединять несколько объектов Try совместно специальным способом, например.

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

и попробовать [Пользователь с Paging] волшебно составленную для меня, но я понятия не имею, как бы я идти об этом - я боролся с системой типа, чтобы попытаться присвоить значимое типа, чтобы «составить» без каких-либо успехов.

Как я могу скомпоновать несколько объектов Try или что-то эквивалентное с помощью конструкции другого языка?

ответ

6

Try s может быть used in for-comprehensions, так как они имеют flatMap функцию:

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

... и не забывайте о том, что 'Future [T]' по существу 'Попробуйте [T]', что hasn Мы закончили еще - мы приняли решение о том, что все наши вызовы на уровне обслуживания возвращают Futures, и это было здорово. Вы получаете все, что «для» -добавления дополнений, плюс он прекрасно вписывается в асинхронную поддержку Play. Даже если конкретная услуга не обязательно должна быть асинхронной, так легко переносить результат в 'Future.successful()', вы также можете! :-) – millhouse

Смежные вопросы