Я верю, что ответ мистера Собрала неверен. Фактические правила можно найти в Scala Language Reference, раздел 6.23, подзаголовок «Синтаксис заполнитель для анонимных функций».
Единственное правило заключается в том, что внутреннее выражение , содержащее символ подчеркивания, определяет область действия анонимной функции. Это означает, что первые два правила г-на Собрала верны, потому что вызов метода является выражением и в скобках выражение не меняет его значения. Но третье правило противоположно истине: при прочих равных условиях будет использовано наименьшее выражение, которое имеет смысл.
К сожалению, мое объяснение поведения г-на Ласковски, наблюдаемое за его первым примером, немного связано и спекулятивно. Когда
List(1,2,3) foreach println(_:Int)
Набирается в виде шкалы для чтения и печати Scala.Сообщение об ошибке:
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
, который после каждого выражения вводится пользователем, вызывает выражение, которое выводится с помощью синтаксического анализатора для печати. (Наряду с большим количеством мусора, который я опущу.) Для первого примера Ласковски в выражение понято парсера
((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
заключается в том, что ее результатом является Unit, а для функции foreach
требуется функция. Как только вы увидите дерево синтаксического анализа, легко увидеть, что это правильно, но мне непонятно, почему дерево разбора является тем, чем оно является.