在Scala中,fun _和fun作为参数有什么区别

时间:2016-12-25 20:39:22

标签: scala

假设我们有一个函数def fun(x: X): X => Y,我们使用fun _而不是fun将此函数作为参数传递给另一个函数。我理解fun _实际上是一个函数值,而fun是指一个函数定义。

例如,让:

val a = List(1,2,3,4)

def fun(x: Int) = {println(x); x + 1}

然后跑步:

//This line works
a.map(fun _)

//This one also works, even though "fun" is not a function value
a.map(fun)

它们具有相同的输出:

1
2
3
4
resX: List[Int] = List(2, 3, 4, 5)

在大多数情况下,它们的工作原理相同,是否存在函数值与函数定义不等的示例?

2 个答案:

答案 0 :(得分:4)

signature of map中,您可以看到它正在等待

  

"功能"适用于每个元素

但是在您的代码中,fun是类中的常规方法。所以当你这样做时:

a.map(fun _)

明确要求进行eta扩展。当你这样做时:

a.map(fun)

隐含地要求进行eta扩展。

由于fun是"方法",并且正在预期使用Function类型的地方使用,因此它automagically converted为{类型。基本上是这样的:

new Function1[Int, Int] {
    def apply(x: Int): Int = fun(x)
}

将名称fun转换为Function的转换称为eta-expansion。有关详细信息,请参阅documentation

不幸的是,有多种方法可以执行您正在执行的操作 - a.map(fun)a.map(fun _)a.map(fun(_))a.map(x => fun(x))。这是Scala中常见的场景之一,您可以自己明确地执行某些操作,或者明确要求编译器为您执行此操作,或者让编译器隐式执行此操作。由于隐含,它们可能具有不同的行为,并且它可能是混淆的主要来源。此外,_在语言中严重超载,只会增加混乱。所以我一般都谨慎地使用隐式行为。

答案 1 :(得分:2)

正如其他人在评论中指出的那样,当需要一个值时,你需要使用fun _语法(执行eta expansion)(方法本身没有价值)。在地图(或其他功能上下文)的上下文中,隐含地对该方法执行eta扩展。在某些情况下,必须手动触发eta扩展。

作为需要显式eta扩展的具体示例,请考虑以下有效代码段:

def f1(x: Int): Int = 2*x

def f2(x: Int): Int = 3*x

val fList1 = List(f1 _, f2 _)

fList1.map(_(2)) // List(4, 6)

而非此无效代码段。

val fList2 = List(f1, f2)