我是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?
感谢您的协助
答案 0 :(得分:4)
让我们把它简化为:
def index(ref: Option[String]): Action[AnyContent] = Prismic.action(ref)(function)
那更好,不是吗? index
是Option
String
Action
AnyContent
action
(一个字)的函数,它调用对象的Prismic
方法{ {1}}传递两个咖喱参数:ref
,index
收到的参数和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
,并返回Action
类AnyContent
。它调用方法action
作为第一个参数Option
,并且作为第二个参数,假定类型为Request
的隐式值请求在范围内。此方法使用For-comprehension调用返回submit
或Option
的{{1}}方法,然后在执行成功的情况下生成结果Future
将被Ok(...)
的{{1}}方法返回的Action
包裹。
答案 2 :(得分:0)
Prismic.action
是一个带有两组参数的方法(a.k.a. currying)。
第一个是ref
第二个是{ implicit request => ...}
,一个在代码块中定义的函数