Confusion about Play framework's code

2019-08-10 06:01发布

问题:

I am a very newbie in Scala area, recently, I am trying to play around the Play framework. I used Play console to generate my first application.

Afterwards, I am reading the code, but for the following code snippets, I just got confused.

package controllers

import play.api._
import play.api.mvc._

object Application extends Controller {

  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }
}

In terms of documentation, Action is a companion object, but what is the syntax for a companion object following curly brackets, is it like the anonymous implementation of an interface in Java, or the content inside curly brackets is the override of apply method?

Please advice, thanks a lot. Sorry for this naive and simple question for Scala veterans.

回答1:

This is syntactic sugar for Action.apply. (You can't have an anonymous implementation of an object, but you could if this were a trait, it would also require new). It has a few overloads:

final def apply[A](bodyParser: BodyParser[A])(block: R[A] => Result): Action[A]

final def apply(block: R[AnyContent] => Result): Action[AnyContent]

final def apply(block: => Result): Action[AnyContent]

Your snippet is using the last of those three. Incidentally, they all return objects implementing the Action[A] trait.



回答2:

Action is a trait that extends EssentialAction

trait Action[A] extends EssentialAction

Essential Action is nothing but a function.Given a RequestHeader, an EssentialAction consumes the request body (an Array[Byte]) and returns a Result.

trait EssentialAction extends (RequestHeader) ⇒ Iteratee[Array[Byte], Result] with Handler

ActionBuilder is a helper trait, which has methods to construct Action. It is this trait that contains multiple overloaded async and apply methods. If you want to define a custom action (or) compose one acction in to other (or) execute one action after other you have to use this trait and Build your own action.

trait ActionBuilder[+R[_]] extends ActionFunction[Request, R]

But what is the syntax like Action{...}. The trait ActionBuilder has a companion Object that also has the same name Action. Note this is different from the train Action[A]. This object overrides InvokeBlock method. In scala, you can define objects as well. You define an object and supply a apply method,which gets called when you call the object.

object Action extends ActionBuilder[Request] {companion
  def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = block(request)
}

What you pass with in braces {...} is nothing but the block defined as a parameter in invokeBlock. In scala you can pass arguments to a function either using parantheses or braces, braces work well when you have a multiline expression like block. This invokeBlock method gets called from an overloaded version of apply in the ActionBuilder trait.

I understand, it is a bit a overwhelming to the get whole point about the thing that goes inside braces, feel easy it took me about 10 days to figure out this. Welcome to Scala !!!

source:

  1. sourcecode -https://github.com/playframework/playframework/blob/2.3.x/framework/src/play/src/main/scala/play/api/mvc/Action.scala

  2. sparse documentation - https://www.playframework.com/documentation/2.3.x/ScalaActionsComposition

  3. play api docs - https://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api.mvc.ActionBuilder

  4. Excellent blog on Action Composition - http://www.mariussoutier.com/blog/2013/09/17/playframework-2-2-action-building-action-composition/