从Play framework任务示例了解Scala函数

从Play framework任务示例了解Scala函数,scala,playframework-2.0,Scala,Playframework 2.0,这是Application.scala中zentask示例中的一个函数。 我正在努力理解它 f:=>字符串是什么意思 那么f:=>String=>Request[AnyContent]=>Result的链接呢 /** * Action for authenticated users. */ def IsAuthenticated(f: => String => Request[AnyContent] => Result) = Security.Authen

这是Application.scala中zentask示例中的一个函数。 我正在努力理解它

f:=>字符串是什么意思

那么f:=>String=>Request[AnyContent]=>Result的链接呢

/** 
 * Action for authenticated users.
 */
def IsAuthenticated(f: => String => Request[AnyContent] => Result) = 
       Security.Authenticated(username, onUnauthorized) { user =>
       Action(request => f(user)(request))
}

格式为
fn:=>String
的参数表示返回(或是)字符串的“生成器”(函数或值),因此,例如,您可以将方法定义为

def myMethod(fn: => String): String = "Fn output = " + fn
如下调用(我在这里使用的返回类型通常可以由编译器推断,我只是出于教学目的添加它们):

在此基础上,我们可以定义一个方法,该方法采用将字符串转换为Int的函数,例如:

def my2ndMethod(fn: String => Int): Int = fn("4")
并称之为:

def my2ndFn(input: String) = 5 * input.toInt
// Alternatively: val my2ndFn: String => Int = input => 5 * input.toInt

val output2 = my2ndMethod(my2ndFn _) // output2 = 20
def authFn(username: String)(request: Request[AnyContent]): Result

val authenticatedResult = IsAuthenticated(authFn _)
在您提供的例子中,您有一个更复杂的实体:它返回(或是)一个接受字符串的函数,并返回另一个函数,该函数依次接受
请求[AnyContent]
,并(最终)返回一个结果(phew!)

您还可以将其视为采用定义和使用如下的函数:

def my2ndFn(input: String) = 5 * input.toInt
// Alternatively: val my2ndFn: String => Int = input => 5 * input.toInt

val output2 = my2ndMethod(my2ndFn _) // output2 = 20
def authFn(username: String)(request: Request[AnyContent]): Result

val authenticatedResult = IsAuthenticated(authFn _)

实际上,要弄清楚操作员是如何关联的有点棘手:

f: => String => Request[AnyContent] => Result

f: (=> String) => (Request[AnyContent] => Result)
因此,
f
是一个函数,它接受一个
=>字符串
,并返回一个函数,该函数接受一个请求并返回一个结果。正如我在评论中所指出的那样,请看一看对发生的一些事情的解释

那么,为什么将
=>String
作为第一个参数而不是
String
?我的猜测是,如果您希望用户通过名称传递具有第一个参数的函数(意味着每次需要时都会对其求值),那么它就起作用了

假设你有一个方法
g

def g(s: => String): String => String = arg => s + arg
如果要编写一个方法
m
,该方法将方法
g
作为参数,则需要这样编写:

def m(f: (=> String) => (String => String)) = f("a")("b")
m(g) // compiles
def n(f: String => (String => String)) = f("a")("b")
n(g) // does not compile
// found   : => String => (String => String)
// required:    String => (String => String)
如果你这样写:

def m(f: (=> String) => (String => String)) = f("a")("b")
m(g) // compiles
def n(f: String => (String => String)) = f("a")("b")
n(g) // does not compile
// found   : => String => (String => String)
// required:    String => (String => String)

请看另一个问题/答案,看看您的问题/答案是否重复:。我花了相当长的时间解释了一个类似的例子。谢谢你澄清了“按姓名传递”的惯例。还有一个问题:在my2ndMethod(my2ndFn_)中下划线的用途是什么?@seand-有关下划线的用途,请参阅我对的回答。本质上,它告诉编译器将函数作为参数传递,而不是计算结果。