我该如何阅读这段Scala(Play)代码?

时间:2014-01-28 15:57:54

标签: scala playframework

我是Scala的新手,我正在通过浏览一些Play代码来学习它。我已经很好地阅读了Scala的主要概念,并且对函数式编程很熟悉Haskell和ML。

我真的很难在语法和编程范例的层面上阅读这段代码。我理解代码应该做什么,但不知道它是如何做的,因为我无法弄清楚语法。

  // -- Home page
def index(ref: Option[String]): Action[AnyContent] = Prismic.action(ref) { implicit request =>
for {
  someDocuments <- ctx.api.forms("everything").ref(ctx.ref).submit()
} yield {
    Ok(views.html.index(someDocuments))
  }
}

(Prismic是一个独立于Play的API,并不是那么相关)。我如何通过电话向另一位开发人员描述这个功能(或者它是一种方法?):换句话说,使用英语。例如,在此代码中:

def add(a: Int, b: Int): Int = a + b

我想说“add是一个带有两个整数的函数,将它们加在一起并将结果作为另一个整数返回”。

在上面的Play代码中,我甚至不知道如何在获取“index是一个函数,它接受一个String的选项并返回一个类型为AnyContent的动作......”之后如何描述它。

'='之后的位,然后是花括号和'=&gt;'吓我!我怎么读它们?是功能还是OO?

感谢您的协助

3 个答案:

答案 0 :(得分:4)

让我们把它简化为:

def index(ref: Option[String]): Action[AnyContent] = Prismic.action(ref)(function)

那更好,不是吗? indexOption String Action AnyContent action(一个字)的函数,它调用对象的Prismic方法{ {1}}传递两个咖喱参数:refindex收到的参数和function(将被描述)。

让我们分解匿名函数:

{ implicit request =>
  for {
    someDocuments <- ctx.api.forms("everything").ref(ctx.ref).submit()
  } yield {
    Ok(views.html.index(someDocuments))
  }
}

首先,它使用{}代替(),因为如果Scala是单个参数(有两个参数列表,但每个都有一个参数列表),Scala允许将()作为参数分隔符参数),该参数包含在{}

那么,{}呢?好吧,它是一个包含声明和语句的表达式,在新行上使用分号推断,其值是最后一个语句的值。也就是说,这两个表达式的值是相同的,3:

{ 1; 2; 3 }
{
  1
  2
  3
}

在传递一个扩展多行的函数时,使用{}是一种语法约定,即使在这种情况下,该函数可以仅使用括号传递。

接下来令人困惑的是implicit request =>,让我们选择更简单的东西:

x => x * 2

这很简单,对吧?它需要一个参数x,并返回x * 2。在我们的例子中,它是相同的:该函数接受一个参数request,并返回:

  for (someDocuments <- somethingSomething())
  yield Ok(views.html.index(someDocuments))

也就是说,它调用一些方法,迭代结果,并将这些结果映射到一个新值。这与Haskell的do符号相当。您可以像下面一样重写它(为了便于阅读,我将其分解为多行):

  ctx
    .api
    .forms("everything")
    .ref(ctx.ref)
    .submit()
    .map(someDocuments => Ok(views.html.index(someDocuments)))

所以,回到我们的方法定义,我们有:

def index(ref: Option[String]): Action[AnyContent] = Prismic.action(ref)(
  implicit request =>
  ctx
    .api
    .forms("everything")
    .ref(ctx.ref)
    .submit()
    .map(someDocuments => Ok(views.html.index(someDocuments)))
)

这里唯一剩下的问题是implicit的含义。基本上,它通过函数的范围隐式提供该参数。据推测,这些方法调用中至少有一个需要一个隐式参数,该参数由request正确地提供。我可以明确地将implicit放在那里request,如果我知道这些方法中哪一个需要它,但是因为我不知道,我正在跳过它。

另一种写作方式是:

def index(ref: Option[String]): Action[AnyContent] = Prismic.action(ref)({
  request =>
  implicit val req = request
  ctx
    .api
    .forms("everything")
    .ref(ctx.ref)
    .submit()
    .map(someDocuments => Ok(views.html.index(someDocuments)))
})

这里我添加了{},因为我在函数体中添加了一个声明,尽管我决定不删掉括号,我可以这样做。

答案 1 :(得分:0)

这样的事情:

index是一个function,其Option String,并返回ActionAnyContent。它调用方法action作为第一个参数Option,并且作为第二个参数,假定类型为Request的隐式值请求在范围内。此方法使用For-comprehension调用返回submitOption的{​​{1}}方法,然后在执行成功的情况下生成结果Future将被Ok(...)的{​​{1}}方法返回的Action包裹。

答案 2 :(得分:0)

  • Prismic.action是一个带有两组参数的方法(a.k.a. currying)。

  • 第一个是ref

  • 第二个是{ implicit request => ...},一个在代码块中定义的函数

more information on Action