Scala:函数值的 eta 扩展(不是方法)

2024-04-21

在尝试了 scala 的 eta 扩展之后,我发现了一个奇怪的功能。 让我们定义一个方法:

scala> def sum(a: Int, b: Int): Int = a + b
sum: (a: Int, b: Int)Int

好吧,到目前为止,一切都很好。现在让我们使用 eta 扩展将其分配给 val:

scala> val f = sum _
f: (Int, Int) => Int = $$Lambda$1051/694580932@55638165

现在,奇怪的事情来了。我可以再次将 eta 扩展应用于 f,并且它正在工作(但是它向我的方法添加了柯里化):

scala> val g = f _
g: () => (Int, Int) => Int = $$Lambda$1055/1351568309@5602e540

为什么这有效?我认为 eta 扩展仅对方法有效。 此外,我注意到这是不可能的:

scala> ((a: Int, b: Int) => a + b: Int) _
<console>:12: error: _ must follow method; cannot follow (Int, Int) => Int
       ((a: Int, b: Int) => a + b: Int) _
                         ^

但这与对 f 应用 eta 展开不是一样吗? 我有点困惑,这些 eta 扩展对我来说仍然隐藏着一些魔力。 多谢 !


当你写的时候val f = sum _在 REPL 或对象/类的顶层,Scala 定义了一个访问器方法,以便您可以访问它。以下是 Scala 脱糖的方法(通过scalac -Xprint:typer on val f: (Int, Int) => Int = _ + _):

private[this] val f: (Int, Int) => Int = ((x$1: Int, x$2: Int) => x$1.+(x$2));
<stable> <accessor> def f: (Int, Int) => Int = Foo.this.f;

所以,当你随后写val g = f _,它对零参数访问器方法进行 eta 扩展,这会导致您看到的行为。为了对此进行更多验证,请注意,如果将定义放入方法中,则会收到错误:

def foo = {
  val f: (Int, Int) => Int = _ + _
  val g = f _ // error: _ must follow method; cannot follow (Int, Int) => Int
}

这是因为访问器仅为字段(以及顶级 REPL 定义,它们被视为字段)生成。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala:函数值的 eta 扩展(不是方法) 的相关文章

随机推荐