我相信索布拉尔先生的回答是不正确的。实际规则可以在Scala Language Reference的第 6.23 节的小标题“匿名函数的占位符语法”中找到。
唯一的规则是正确包含下划线的最里面的表达式定义了匿名函数的范围。这意味着 Sobral 先生的前两条规则是正确的,因为方法调用是一个表达式,给表达式加上括号并不会改变其含义。但是第三条规则与事实相反:在所有其他条件相同的情况下,将使用有意义的最小表达式。
不幸的是,我对 Laskowski 先生在他的第一个例子中观察到的行为的解释有点牵强和推测。什么时候
List(1,2,3) foreach println(_:Int)
在 Scala 的 read-eval-print 循环中输入。错误信息是:
error: type mismatch;
found : Unit
required: Int => ?
List(1,2,3) foreach println(_:Int)
^
如果您稍微改变示例:
List(1,2,3).foreach println(_:Int)
错误信息更容易理解——
error: missing arguments for method foreach in class List;
follow this method with `_' if you want to treat it as a partially applied function
List(1,2,3).foreach println(_:Int)
^
为了更好地理解事情,scala
这样调用: scala -Xprint:parser
,在用户输入每个表达式之后,会导致解析器充实的表达式被打印出来。(还有很多垃圾,我将省略。)对于 Laskowski 的第一个示例,解析器理解的表达式是
((x$1: Int) => List(1, 2, 3).foreach(println((x$1: Int))))
对于第二个示例,解析器的版本是
((x$1: Int) => List(1, 2, 3).foreach.println((x$1: Int)))
显然,范围规则是在表达式结构完全充实之前应用的。在这两种情况下,解析器都猜测最小的表达式从 List 开始,即使插入括号后就不再正确了。在第二个例子中,除了这个假设之外,它还假设,因为println
是一个标识符,foreach println
是一个方法链,第一个没有参数。然后在处的错误foreach
之前捕获错误println
,将其屏蔽。错误println
在于它的结果是单位,并且foreach
需要一个函数。一旦您看到解析树,就很容易看出这是正确的,但是(对我而言)不清楚为什么解析树是这样的。