38

我是 Scala 的新手。刚刚听说过“eta扩展”这个词,大致知道就是将一个方法扩展为一个函数对象。但我在 SO 中发现很少有系统地介绍它的资源。

我很好奇 eta 扩展如何在 Scala 中工作。需要eta扩容的场景有哪些?以及如何在 Scala 中实现eta 扩展?

我大致知道在这种情况下:

def someMethod(x: Int): Int = x * x

someMethod _将大致翻译成一个新的函数对象,如下所示:

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

这就是 Scala 所做的一切吗?

4

2 回答 2

29

定义和一些示例在http://scala-lang.org/files/archive/spec/2.11/06-expressions.html#method-values中给出。

someMethod _将大致翻译成一个新的函数对象,如下所示:

不完全是:实际上是

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

差异很重要,例如是否someMethod在某处被覆盖。

这就是 Scala 所做的一切吗?

您还需要考虑如果该方法采用多个参数列表(您得到一个返回函数的函数)或按名称参数会发生什么。

需要eta扩容的场景有哪些?

  1. 当您特别要求时(例如someMethod _)。

  2. 当您使用一个方法(带参数)时,需要一个函数类型(或 Scala 2.12 中的 SAM 类型)的值。例如

    def foo(f: Int => Int) = ???
    
    foo(someMethod)
    
  3. 而已。

someMethod(_)请注意,由于类型推断、隐式等原因,使用 eta-expansion 和带有占位符 ( ) 的匿名函数可能会有不同的行为。

于 2016-09-12T09:17:26.503 回答
20

Eta 扩展在高层次上,是将方法转换为函数的过程。为什么?什么?他们不一样吗?让我们解释一下:

Scala 中的一个方法就是我们所知道的def someMethodName(SomePramList): SomeReturnType. 它以def. 它可能有参数列表,甚至可能超过 1 个。例如:

def numAdder(num1: Int)(num2: Int): Int = 
    num1 + num2

一个functionlambdafunction 看起来像:(SomeParams) => SomeReturnType. 例如:

val aFunction: Int => Int => Int = (num1: Int) => (num2: Int) => num1 + num2

了解函数的重要一点是,这种语法基本上是FunctionN.apply方法的语法糖。

需要eta扩容的场景有哪些?

一些例子:

示例 1 - 在内部map(或filterflatMap)应用方法

编写这样的代码:

def addPlus1(x: Int): Int = x + 1
List(1,2,3).map(addPlus1)

编译器需要在map. 因此,它将给定的方法转换为函数: List(1,2,3).map(x => addPlus1(x)). 这是Eta expansion.

示例 2 - 柯里化

定义柯里化方法时,例如:

def numAdder(num1: Int)(num2: Int): Int = 
    num1 + num2

他们创建了一个函数,例如:

val curriedFunction: Int => Int = numAdder(4)
//or
val curriedFunction2 = numAdder(4) _

我们从方法中定义了一个函数。这是Eta expansion.

更多示例

定义了一个接受函数值的方法:

def someMethod(f: () => Int): Int = f()
def method(): Int = 10

然后运行:

someMethod(method)

将方法method转换为函数。这是Eta expansion

于 2020-06-28T08:50:45.363 回答