男孩,这是一个微妙的,但据我所知,它完全遵循Scala 规范。我将引用规范的 2.9 版。
对于您的第一个示例:正如您正确地说的那样,您通过方法值的特殊情况(第 6.7 节)看到 eta 扩展:
The expression e _ is well-formed if e is of method type or if e is a call-by-name parameter. If e is a method with parameters, e _ represents e converted to a function type by eta expansion.
eta 扩展的算法在 §6.26.5 中给出,您可以按照它对表达式进行以下替换new Foo().x1 _
:
{
val x1 = new Foo();
(y1: Int) => x1.(y1);
}
这意味着当使用 eta 扩展时,所有子表达式都在转换发生的点进行评估(如果我正确理解了短语“最大子表达式”的含义)并且最终表达式是创建一个匿名函数。
在您的第二个示例中,那些额外的括号意味着编译器将查看 §6.23(特别是“匿名函数的占位符语法”)并直接创建一个匿名函数。
An expression (of syntactic category Expr) may contain embedded underscore symbols _ at places where identifiers are legal. Such an expression represents an anonymous function where subsequent occurrences of underscores denote successive parameters.
在这种情况下,按照该部分中的算法,您的表达式最终会变成这样:
(x1: Int) => new Foo().foo(x1)
差异是微妙的,正如@Antoras 很好解释的那样,实际上只有在存在副作用代码的情况下才会显示出来。
请注意,对于涉及按名称调用代码块的案例(例如,请参阅此问题、此错误和此错误),正在进行错误修复。
后记:在这两种情况下,匿名函数(x1:Int) => toto
都被扩展为
new scala.Function1[Int, Int] {
def apply(x1: Int): Int = toto
}