为什么以下Play语法有效
def handleForm = Action(parse.tolerantFormUrlEncoded) { implicit request =>
val username = request.body.get("username").map(_.head).getOrElse("");
Ok("Username was " + username)
}
如果没有指定请求的类型,编译器将如何知道如何解析隐式?
答案 0 :(得分:2)
Play中的动作可视为一项功能:Request[A] => Result
。在内部,Action定义为trait Action[A] extends EssentialAction
类型A
实际上是允许您在其中放置任何内容的类型。从代码中可以看出,Request的定义如下:trait Request[+A] extends RequestHeader
。这里有趣也是加号(+
)。它就是所谓的协变注释。该协变类型参数是在类被子类型时允许变化的参数。这意味着,如果你有类似
trait List[+A]
然后List[Int]
是List[AnyVal]
的子类型,因为Int
是AnyVal
的子类型。这意味着,当预期值为List[Int]
的值时,您可以提供List[AnyVal]
的实例。
所有这些都允许您拥有一个超级通用请求,作为您的操作的基础,因此不应该出现编译时间问题。
从一个更加用户相关的角度来看,为什么这一切都是必要的:
来自Play Scala文档:
将请求参数标记为隐式通常很有用 被其他需要它的API隐式使用:
Action { implicit request => Ok("Got request [" + request + "]") }
答案 1 :(得分:2)
对于请求处理程序中的进一步方法调用,它实际上并没有解析隐式的你将参数标记为隐式。每当您调用接受隐式Request
参数的方法时,请求处理程序中的请求参数将自动传递给它。如果您不将请求参数标记为隐式,则必须为需要隐式请求参数的每个方法调用显式传递请求参数。
更新:根据您的评论,我使用类型参数更新您的代码以澄清。所以即使你使用不同的BodyParser
s,你的请求参数仍然是Request类型,所以不需要转换它,它只是根据你的身体解析器进行不同的参数化。 request.body
将与此示例中的类型参数Map[String, Seq[String]]
具有相同的类型。如果您使用JSON正文解析器,则request
参数将为Request[JsValue]
,request.body
为JsValue
。
def handleForm: Action[Map[String, Seq[String]]] = Action(parse.tolerantFormUrlEncoded)({
implicit request: Request[Map[String, Seq[String]]] =>
val username = request.body.get("username").map(_.head).getOrElse("")
Ok("Username was " + username)
})
tl; dr 如果您在请求处理程序中不需要隐式Action(...) { request => ... }
进行进一步的方法调用,则可以执行Request