没有类型的隐含参数

时间:2015-12-20 08:51:08

标签: scala playframework implicit

为什么以下Play语法有效

def handleForm = Action(parse.tolerantFormUrlEncoded) { implicit request =>
  val username = request.body.get("username").map(_.head).getOrElse("");
  Ok("Username was " + username)
}

如果没有指定请求的类型,编译器将如何知道如何解析隐式?

2 个答案:

答案 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]的子类型,因为IntAnyVal的子类型。这意味着,当预期值为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.bodyJsValue

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