"Action" 这个词在使用 Play 框架的 Scala 函数定义中有什么作用?
What does the word "Action" do in a Scala function definition using the Play framework?
我正在开发 Play 应用程序,并且刚开始使用 Scala。我看到下面的函数中等号之后和大括号之前有这个词 Action
。
def index = Action {
Ok(views.html.index("Hi there"))
}
这段代码有什么作用?我见过它与 def index = {
一起使用,但没有与花括号前的单词一起使用。
我假设函数的名称是 index
。但我不知道 Action
这个词在这种情况下的作用。
它是 Action
以表达式块作为参数调用。 (apply
方法在后台使用)。
Action.apply({
Ok("Hello world")
})
一个简单的例子(来自here)如下(看代码中的注释):
case class Logging[A](action: Action[A]) extends Action[A] {
def apply(request: Request[A]): Result = {// apply method which is called on expression
Logger.info("Calling action")
action(request) // action being called on further with the request provided to Logging Action
}
lazy val parser = action.parser
}
现在您可以使用它来包装任何其他操作值:
def index = Logging { // Expression argument starts
Action { // Action argument (goes under request)
Ok("Hello World")
}
}
此外,您为 def index = {
提到的案例实际上返回了 Unit
,例如:def index: Unit = {
.
这个词是 Play Framework 的一部分,它是一个 object,它有方法 apply(block: ⇒ Result)
,所以你的代码实际上是:
def index: Action[AnyContent] = Action.apply({
Ok.apply(views.html.index("Hi there"))
})
您的 index
方法 return 是 class Action[AnyContent]
的一个实例。
顺便说一句,您正在将代码块 {Ok(...)}
传递给 apply
方法,该方法(代码块)在这里实际上充当匿名函数,因为 apply
的输入不仅仅是Result
而是⇒ Result
,这意味着它接受一个没有输入参数的匿名函数,即returns Result
。因此,当容器收到您的 class Action
实例(来自索引方法)时,您的 Ok 块将被执行,决定执行此块。这只是意味着您只是在此处描述一个动作 - 而不是执行 - 它会在 Play 收到您的请求时实际执行 - 并在路由文件中找到与您的动作的绑定。
此外,您不必在此处使用 def
,因为您总是 return 相同的操作 - val
或 lazy val
通常就足够了。仅当您确实想从路由 table 传递一些参数时才需要 def
(例如):
GET /clients/:id controllers.SomeController.index(id: Long)
def index(id: Long) = Action { ... } // new action generated for every new request here
另一种可能的方法是根据参数选择操作:
def index(id: Long) = {
if (id == 0) Action {...} else Action{...}
}
但通常你可以使用路由 table 本身,这对于解耦更好。这个例子只是表明 Action
只不过是 return 值。
更新@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
}
GWT/Scala.js 使用类似的方法进行客户端-服务器交互。这只是解释从路由 table 传递的参数 "methodName" 的重要性的一种可能解决方案。因此,action 可以被认为是函数的包装器,它又代表了对 OOP 方法的引用,这使得它对 REST 和 RPC 都很有用。
其他答案针对您的具体情况。但是,您问的是一般情况,所以我会尝试从这个角度回答。
首先,def
用于定义一个方法,not a function(现在最好了解一下区别)。但是,你是对的,index
是该方法的名称。
现在,与您可能熟悉的其他语言(例如 C,Java)不同,Scala 允许您使用表达式定义方法(如使用赋值运算符语法所建议的那样,=
).也就是说,=
之后的所有内容都是一个 expression,每次调用该方法时都会将其计算为 value。
因此,在 Java 中你必须说:
public int three() { return 3; }
在 Scala 中,你可以直接说:
def three = 3
当然,表达式通常更复杂(如您的情况)。它可能是一段代码,就像您更习惯看到的那样,在这种情况下,值是块中最后一个表达式的值:
def three = {
val a = 1
val b = 2
a + b
}
或者它可能涉及对某个其他对象的方法调用:
def three = Numbers.add(1, 2)
实际上,后者正是您的具体示例中发生的事情,尽管需要更多解释才能理解原因。涉及两个魔法:
- 如果一个对象有一个
apply
方法,那么您可以将该对象视为一个 函数。例如,您可以说 Add(1, 2)
,而您真正的意思是 Add.apply(1,2)
(当然,假设有一个带有 apply
方法的 Add
对象)。需要明确的是,它不一定是使用 object
关键字定义的对象。任何具有合适 apply
方法的对象都可以。
- 如果一个方法只有一个 by-name 参数(例如,
def ifWaterBoiling(fn: => Tea)
),那么您可以像 ifWaterBoiling { makeTea }
一样调用该方法。该块中的代码被延迟评估(并且可能根本不被评估)。这相当于写 ifWaterBoiling({ makeTea })
。 { makeTea }
部分只是定义了一个表达式,它被传入,未计算,用于 fn
参数。
我正在开发 Play 应用程序,并且刚开始使用 Scala。我看到下面的函数中等号之后和大括号之前有这个词 Action
。
def index = Action {
Ok(views.html.index("Hi there"))
}
这段代码有什么作用?我见过它与 def index = {
一起使用,但没有与花括号前的单词一起使用。
我假设函数的名称是 index
。但我不知道 Action
这个词在这种情况下的作用。
它是 Action
以表达式块作为参数调用。 (apply
方法在后台使用)。
Action.apply({
Ok("Hello world")
})
一个简单的例子(来自here)如下(看代码中的注释):
case class Logging[A](action: Action[A]) extends Action[A] {
def apply(request: Request[A]): Result = {// apply method which is called on expression
Logger.info("Calling action")
action(request) // action being called on further with the request provided to Logging Action
}
lazy val parser = action.parser
}
现在您可以使用它来包装任何其他操作值:
def index = Logging { // Expression argument starts
Action { // Action argument (goes under request)
Ok("Hello World")
}
}
此外,您为 def index = {
提到的案例实际上返回了 Unit
,例如:def index: Unit = {
.
这个词是 Play Framework 的一部分,它是一个 object,它有方法 apply(block: ⇒ Result)
,所以你的代码实际上是:
def index: Action[AnyContent] = Action.apply({
Ok.apply(views.html.index("Hi there"))
})
您的 index
方法 return 是 class Action[AnyContent]
的一个实例。
顺便说一句,您正在将代码块 {Ok(...)}
传递给 apply
方法,该方法(代码块)在这里实际上充当匿名函数,因为 apply
的输入不仅仅是Result
而是⇒ Result
,这意味着它接受一个没有输入参数的匿名函数,即returns Result
。因此,当容器收到您的 class Action
实例(来自索引方法)时,您的 Ok 块将被执行,决定执行此块。这只是意味着您只是在此处描述一个动作 - 而不是执行 - 它会在 Play 收到您的请求时实际执行 - 并在路由文件中找到与您的动作的绑定。
此外,您不必在此处使用 def
,因为您总是 return 相同的操作 - val
或 lazy val
通常就足够了。仅当您确实想从路由 table 传递一些参数时才需要 def
(例如):
GET /clients/:id controllers.SomeController.index(id: Long)
def index(id: Long) = Action { ... } // new action generated for every new request here
另一种可能的方法是根据参数选择操作:
def index(id: Long) = {
if (id == 0) Action {...} else Action{...}
}
但通常你可以使用路由 table 本身,这对于解耦更好。这个例子只是表明 Action
只不过是 return 值。
更新@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
}
GWT/Scala.js 使用类似的方法进行客户端-服务器交互。这只是解释从路由 table 传递的参数 "methodName" 的重要性的一种可能解决方案。因此,action 可以被认为是函数的包装器,它又代表了对 OOP 方法的引用,这使得它对 REST 和 RPC 都很有用。
其他答案针对您的具体情况。但是,您问的是一般情况,所以我会尝试从这个角度回答。
首先,def
用于定义一个方法,not a function(现在最好了解一下区别)。但是,你是对的,index
是该方法的名称。
现在,与您可能熟悉的其他语言(例如 C,Java)不同,Scala 允许您使用表达式定义方法(如使用赋值运算符语法所建议的那样,=
).也就是说,=
之后的所有内容都是一个 expression,每次调用该方法时都会将其计算为 value。
因此,在 Java 中你必须说:
public int three() { return 3; }
在 Scala 中,你可以直接说:
def three = 3
当然,表达式通常更复杂(如您的情况)。它可能是一段代码,就像您更习惯看到的那样,在这种情况下,值是块中最后一个表达式的值:
def three = {
val a = 1
val b = 2
a + b
}
或者它可能涉及对某个其他对象的方法调用:
def three = Numbers.add(1, 2)
实际上,后者正是您的具体示例中发生的事情,尽管需要更多解释才能理解原因。涉及两个魔法:
- 如果一个对象有一个
apply
方法,那么您可以将该对象视为一个 函数。例如,您可以说Add(1, 2)
,而您真正的意思是Add.apply(1,2)
(当然,假设有一个带有apply
方法的Add
对象)。需要明确的是,它不一定是使用object
关键字定义的对象。任何具有合适apply
方法的对象都可以。 - 如果一个方法只有一个 by-name 参数(例如,
def ifWaterBoiling(fn: => Tea)
),那么您可以像ifWaterBoiling { makeTea }
一样调用该方法。该块中的代码被延迟评估(并且可能根本不被评估)。这相当于写ifWaterBoiling({ makeTea })
。{ makeTea }
部分只是定义了一个表达式,它被传入,未计算,用于fn
参数。