"Action"一词在使用Play框架的Scala函数定义中做了什么?

Joh*_*ton 12 scala playframework

我正在开发Play应用程序,我刚开始使用Scala.我看到Action在下面的函数和大括号之前的等号之后有这个单词.

def index = Action {
  Ok(views.html.index("Hi there"))
}
Run Code Online (Sandbox Code Playgroud)

这段代码有什么作用?我已经看到它与def index = {大括号之前的单词一起使用但没有使用.

我假设函数的名称是index.但我不知道Action在这种情况下这个词是做什么的.

dk1*_*k14 16

这个词是Play Framework的一部分,它是一个具有方法的对象apply(block: ? Result),所以你的代码实际上是:

def index: Action[AnyContent] = Action.apply({
  Ok.apply(views.html.index("Hi there"))
})
Run Code Online (Sandbox Code Playgroud)

您的index方法返回该类 的实例Action[AnyContent].

顺便说一句,你传递一个块的代码{Ok(...)}apply方法,它(的代码块)实际上是在这里充当匿名函数,因为所需要的类型apply的输入不仅仅是Result但是? Result,这意味着它需要一个匿名函数没有输入参数,返回Result.因此,当容器接收到您的类实例Action(来自索引方法)时,您的Ok块将被执行,决定执行此块.这只是意味着你只是在这里描述一个动作 - 而不是执行 - 它将在Play收到你的请求时实际执行 - 并找到你在路由文件中的动作的绑定.

此外,您不必def在此处使用,因为您总是返回相同的操作 - val或者lazy val通常就足够了.def如果您确实想要从路由表中传递一些参数(例如),则只需要一个:

GET   /clients/:id          controllers.SomeController.index(id: Long)

def index(id: Long) = Action { ... } // new action generated for every new request here
Run Code Online (Sandbox Code Playgroud)

另一种可能的方法是根据参数选择Action:

def index(id: Long) = {
   if (id == 0) Action {...} else Action{...}
}
Run Code Online (Sandbox Code Playgroud)

但是你可以使用路由表本身,这对于解耦更好.这个例子只是表明它Action只不过是返回值.


@Kazuya更新

 val method1 = Action{...} //could be def too, no big difference here

 // this (code inside Action) gonna be called separately after "index" (if method2 is requested of course)
 // notice that it needs the whole request, so it (request) should be completely parsed at the time
 val method2 = Action{ req => // you can extract additional params from request
   val param1 = req.headers("header1")
   ...
 }

 //This is gonna be called first, notice that Play doesn't need the whole request body here, so it might not even be parsed on this stage
 def index(methodName: String) = methodName match {
   case "method1" => method1
   case "method2" => method2
 }
Run Code Online (Sandbox Code Playgroud)

GWT/Scala.js使用simillar方法进行客户端 - 服务器交互.这只是解释从路由表传递的参数"methodName"的重要性的一种可能的解决方案.因此,action可以被认为是函数的包装器,它反过来表示对OOP方法的引用,这使得它对REST和RPC都有用.


Aar*_*rup 11

其他答案涉及您的具体案例.但是,您询问了一般情况,因此我将尝试从这个角度回答.

首先,def用来定义一个方法,不是一个函数(最好现在得知差).但是,你是对的,index是那种方法的名称.

现在,与您可能熟悉的其他语言(例如,C,Java)不同,Scala允许您使用表达式定义方法(通过使用赋值运算符语法建议=).也就是说,之后的所有内容=都是一个表达式,每次调用该方法时都会对其求.

所以,在Java中你必须说:

public int three() { return 3; }
Run Code Online (Sandbox Code Playgroud)

在Scala中,您可以说:

def three = 3
Run Code Online (Sandbox Code Playgroud)

当然,表达式通常更复杂(如您的情况).它可能是一段代码,就像你更习惯看到的那样,在这种情况下,值是块中最后一个表达式的值:

def three = {
   val a = 1
   val b = 2
   a + b
}
Run Code Online (Sandbox Code Playgroud)

或者它可能涉及对其他一些对象的方法调用:

def three = Numbers.add(1, 2)
Run Code Online (Sandbox Code Playgroud)

事实上,后者正是你的具体例子中正在发生的事情,尽管它需要更多的解释来理解为什么.涉及两个魔法:

  1. 如果对象具有apply方法,则可以将对象视为函数.例如,你可以说,Add(1, 2)当你真正的意思时Add.apply(1,2)(假设有Add一个apply方法的对象,当然).而且要清楚,它不必是使用object关键字定义的对象.任何具有合适apply方法的对象都可以.
  2. 如果方法具有单个by-name参数(例如,def ifWaterBoiling(fn: => Tea)),则可以调用方法ifWaterBoiling { makeTea }.该块中的代码被懒惰地评估(并且可能根本不被评估).这相当于写作ifWaterBoiling({ makeTea }).该{ makeTea }部分只定义了一个表达式,该表达式为fn参数传入,未经评估.