2016-12-25 83 views
1

可以说我们有一个函数def fun(x: X): X => Y,我们通过fun _而不是fun将这个函数作为参数传递给另一个函数。我明白fun _实际上是一个函数值,而fun是指一个函数定义。在Scala中,乐趣_和乐趣之间的区别是什么

例如让:

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) 

在大多数情况下,他们似乎工作一样,是有没有任何函数值不等于函数定义的例子?

+1

'fun'是一种方法,而不是一种功能。区别很重要。 – rightfold

+3

的可能的复制[什么是Scala的ETA膨胀?](http://stackoverflow.com/questions/39445018/what-is-the-eta-expansion-in-scala) – Haspemulator

+0

发布一个实际的例子示出了“我们通过这个函数作为另一个函数的参数,使用'fun _'而不是'fun'“和”大部分它们看起来都是一样的“。这对我们来说会更容易。 http://stackoverflow.com/help/mcve – YoungSpice

回答

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) 
+1

'val fList2:List [Int => Int] = List(f1,f2)'也可以。 –

+0

是否有隐式转换? –

+0

编译器每当它看到一个预期函数的方法时执行η-扩展,在这种情况下'List'元素的类型应该是'Int => Int'类型。 –

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中那些经常出现的场景之一,您可以自己明确地做某些事情,或者明确要求编译器为您做,或者让编译器隐式执行。他们可能因为隐含而有不同的行为,并且可能是混淆的主要来源。另外,_在语言中严重超载,只会增加混淆。所以我一般使用隐含的行为。