Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Scala中,使用下划线创建闭包的规则是什么?_Scala_Scala Placeholder Syntax_Eta Expansion - Fatal编程技术网

在Scala中,使用下划线创建闭包的规则是什么?

在Scala中,使用下划线创建闭包的规则是什么?,scala,scala-placeholder-syntax,eta-expansion,Scala,Scala Placeholder Syntax,Eta Expansion,起初,我认为使用下划线来生成闭包(例如println\uu)只是使用箭头(例如x=>println x)的简写形式,但我最近才了解到,您还可以执行以下操作: def f(a: Int, b: Int) = a + 2 * b List(1, 2, 3).reduce(f _) 根据我过去的假设,f看起来像一个闭包,只接受一个参数,并将一个参数传递给f。我假设它会告诉我它无法编译,因为f需要两个参数,而reduce应该需要一个有两个参数的函数。但它就像我写的: def f(a: Int, b:

起初,我认为使用下划线来生成闭包(例如
println\uu
)只是使用箭头(例如
x=>println x
)的简写形式,但我最近才了解到,您还可以执行以下操作:

def f(a: Int, b: Int) = a + 2 * b
List(1, 2, 3).reduce(f _)
根据我过去的假设,
f
看起来像一个闭包,只接受一个参数,并将一个参数传递给
f
。我假设它会告诉我它无法编译,因为
f
需要两个参数,而
reduce
应该需要一个有两个参数的函数。但它就像我写的:

def f(a: Int, b: Int) = a + 2 * b
List(1, 2, 3).reduce((x, y) => f(x, y))

这是怎么回事?创建带下划线的闭包的规则是什么?

没有什么特别的。方法
reduce
使用一个函数,该函数使用两个
Int
s并生成一个
Int
,因此为它提供一个
f
很好。请注意,当您说
f
时,它实际上扩展为
x=>fx
(或者,对于这里这样的两个参数,
(x,y)=>f(x,y)
)。您也可以只提供
f
,然后直接使用,而不需要额外的匿名函数包装器

通过执行
f 
将方法转换为函数被调用(完全公开:我写了那篇文章)。差异是微妙的;函数是一个值,而方法是一个方法,您可以在为其定义的对象上调用它,例如
myObject.myMethod
。函数可以独立存在,可以保存在集合中等。将方法
f
直接定义为函数将是
valf:(Int,Int)=>Int=(a:Int,b:Int)=>a+b
或者,通过类型推断,
valf=(a:Int,b:Int)=>a+b


顺便说一句,我不认为这是一个闭包。

在你的例子中,
f 
是一个使用eta扩展机制的函数类型。也就是说,它将方法
f(a:Int,b:Int):Int
转换为
(Int,Int)=>Int
(即a
Function2[Int,Int,Int]
),这是一个提供reduce的有效类型。(另外,作为一个简要说明,您的函数不是关联的,这打破了reduce所要求的契约)@math4tots,请注意
f
f(
是两件不同的事情。部分应用的函数和eta扩展之间有什么区别?例如,
val k=f
,这不也是一个部分应用的函数吗?@ceran否。部分应用的函数将是
f(42,:Int)
。或者如果它的格式是
def(a:Int)(b:Int)
,那么你可以说
f(42)\uu
。但是仅仅说
f
就意味着一个方法
f
将被转换成一个函数。另请参阅我的答案中的编辑以获得进一步的澄清。嗯,我看不出有什么区别。奥德斯基的Scala书说,在
list.foreach(println)
中,
println(u
表示一个部分应用的函数。你根本不需要提供任何论据。你是对的,我的措辞是错误的。是的,从技术上讲,这是一个部分应用的功能。即使是编译器也会告诉您“如果您想将其视为部分应用的函数,请添加”。我的意思是,
f
将采用您的方法,执行eta扩展(也就是说,通过将其包装成
x=>fx
,将其转换为函数
Int=>Int
),然后它将对其应用零参数,从而使其成为部分应用的函数。如果你考虑一个函数为零参数的PAF,那么每个函数都是一个PAF,这有点误导,但是,技术上你是正确的。所以,改进了你之前的问题的答案——PAF是一个函数,它是通过部分地应用一些现有函数而不提供所有参数而产生的。(如果应用了所有参数,则它不再是“部分应用的”,事实上也不再是函数,而是函数返回的值)。Eta扩展是获取函数并将其包装到另一个函数中的过程,例如,获取
Math.sqrt(x)
并将其包装到
x=>Math.sqrt(x)中
。它们都取一些
Int
并返回其平方根。Eta exp由编译器在将方法转换为函数时执行。