24

对于我所知道的微不足道的事情,我很难找到具体的答案。我想了解块在 Scala 中是如何工作的。我来自 java/ruby 背景,似乎 scala 使用块的方式完全不同。

以下代码来自Play! 框架网站。我想从语义上理解Action是什么。它是接受块的对象还是函数,或者两者都不是。

object Application extends Controller {

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

}

如果它是一个函数,也许它是以下的语法糖(在这种情况下,scala 如何在幕后传递块):

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

还是我不知道的一些scala语法。

对 Scala 源代码的任何引用都将帮助我理解它是如何在幕后工作的。

4

2 回答 2

24

您最好将 scala 块视为 java 匿名类(例如 Guava Functions)而不是 ruby​​ 块。实际上,如果您反编译 scala 代码,您将看到或多或少相同的代码(取自 Guava 示例):

Function<String, Integer> lengthFunction = new Function<String, Integer>() {
  public Integer apply(String string) {
    return string.length();
  }
};

不同之处在于 scala 提供了很多语法糖,并允许您将上面的代码编写为:

val lengthFunction = { string: String => string.length }

至于具体的 Action 例子:

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

这里 Action 可能是带有 apply 方法的对象。另一种 scala 糖:语言允许你书写Foo(bar)和表示Foo.apply(bar). 接下来,当您的调用不明确时,您可以删除圆括号,所以是的,它实际上是一个被调用的方法,如下所示:

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

并有这样的东西作为签名:

object Action {
  def apply(block: => Result) = ???
}

正如@yan 已经说过的那样,这是 scala 方式说嘿,我是一个接受另一个产生 Result 的函数的函数

脱糖调用看起来像

def index = Action.apply(new AbstractFunction[Result] {
        def apply() = Ok.apply(views.html.index.apply("..."))
})
于 2013-09-25T15:35:46.443 回答
8

这里发生了一些事情。Action是实现apply()方法的对象,当您将对象视为函数时会调用什么。有几个apply() 实现。第一个实现使用按名称参数。

Scala 支持称为“按名称参数”的概念,它与普通参数一样,只是它们仅在执行引用它们的代码时才被评估。它们有助于创建看起来像是语言的一部分的结构,而无需借助宏。在这种情况下,块周围Ok(..)只是一个常规的语句块,最后一个的值被用作块的值。您提供的示例在没有大括号的情况下也可以工作。您本质上只是将 Okapply方法的结果传递给Action'apply方法。

第二个版本apply()确实采用了一个完整的匿名函数,它将请求映射到结果。在这种情况下,您可以传递一个匿名(或命名)函数。

于 2013-09-25T14:31:57.183 回答