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

In Scala, what are the rules for making closures with underscores?

一开始我以为用下划线做闭包(例如println _)只是shorthand用箭头(例如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 并生成一个 Int,因此为它提供一个 f 可以正常工作。请注意,当您说 f _ 时,实际上会扩展为 x => f x(或者,如果有两个参数,例如此处,(x, y) => f(x, y))。您也可以只提供 f ,然后将直接使用它,而无需额外的匿名函数包装器。

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

顺便说一句,我不明白这是一个闭包。