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

mat*_*ots 3 scala scala-placeholder-syntax eta-expansion

起初我曾相信使用下划线来制作闭包(例如println _)只是使用箭头的简写(例如x => println x),但我最近才知道你也可以做以下事情:

def f(a: Int, b: Int) = a + 2 * b
List(1, 2, 3).reduce(f _)
Run Code Online (Sandbox Code Playgroud)

鉴于我过去的假设,f _看起来像一个闭包,它只接受一个参数并且只传递一个参数f.我以为它会告诉我它无法编译因为f需要两个参数,并且reduce应该期望一个带有两个参数的函数.但是就像我写的那样:

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

这里发生了什么?使用下划线创建闭包的规则是什么?

slo*_*ouc 5

没什么特别的.方法reduce采用一个函数,需要两个Ints并产生一个Int,所以提供它f工作正常.请注意,当您说f _实际扩展为x => f x(或者,如果有两个参数,例如此处(x, y) => f(x, y)).您也可以只提供f直接使用的内容,而无需额外的匿名函数包装器.

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

顺便说一下,我不知道这是一个封闭.