Я постараюсь извлечь суть из вашего примера.
Рассмотрим следующий фрагмент кода:
{ val x = 1 { val y = 2 } }
Для компилятора это выглядит как синтаксический сахар для
{ val x = 1.apply({ val y = 2 }) }
Но у объекта 1
нет метода apply
, который принимает блоки, поэтому компилятор выдает ошибку:
ошибка: Int (1) не принимает параметры
{ val x = 1 { val y = 2 } }
^
Сравните это с
object I { def apply(a: => Any): Unit = () }
{ val x = I { val y = 2 } }
Это работает, потому что I
сейчас имеет метод apply
.
Чтобы немного облегчить различие между этими двумя случаями, компилятору в первом случае требуется точка с запятой.
Теперь можно задаться вопросом, почему разрыв строки между val x = 1
и {
не преобразуется в предполагаемую точку с запятой. Я думаю, что соответствующая цитата из спецификации была бы такой ( 1.2 Символы новой строки ) (большинство частей перечислений опущено ([...]
), выделено мое):
Грамматика Scala [...] содержит произведения, в которых
необязательные nl
токены, но не точки с запятой, принимаются. Это имеет
эффект, что символ новой строки в одной из этих позиций не завершает
выражение или утверждение . Эти позиции можно обобщить следующим образом:
[...]
перед открывающей скобкой ‘{’, , если эта скобка является законным продолжением текущего оператора или выражения ,
[...]
Обратите внимание, что эта цитата охватывает только случай с одиночным необязательным переводом строки. Он не действует в течение двух или более последовательных разрывов строк, например,
scala> {
| val x = 1
|
| { val y = 2 }
| }
допустимо, а { val y = 2 }
анализируется как отдельное выражение.
I думаю мотивация состояла в том, чтобы разрешить встроенные DSL с синтаксическим сахаром, как это:
MY_WHILE(x >= 0)
{
println(x)
x -= 1
}
Было бы очень странно, если бы каждый из этих MY_WHILE
операторов заключал в дополнительную пару круглых скобок, не так ли?