Это совсем не странно. Давайте посмотрим на первый пример:
Вы объявляете свой класс ABC
для получения параметра передачи по имени, который возвращает Unit
, и вы думаете, что этот фрагмент:
val x = new ABC {
a + b
}
передает этот параметр body
, нет. На самом деле происходит следующее:
val x = new ABC(()) { a + b }
Если вы запустите этот код, вы увидите, что println(body)
prints (), потому что вы не передаете значение для вашего параметра body
, компилятор разрешает его компилировать, потому что, как утверждает scaladoc, есть только 1 значение введите Unit
:
Unit является подтипом scala.AnyVal. Существует только одно значение типа Unit (()), и оно не представлено никаким объектом в базовой системе выполнения. Метод с возвращаемым типом Unit аналогичен методу Java, объявленному пустым.
Поскольку есть только одно значение, компилятор позволяет вам опустить его, и оно заполнит пробел. Этого не происходит с одноэлементными объектами, потому что они не расширяют AnyVal
. Просто значение по умолчанию для Int
равно 0
, значение по умолчанию для Unit
равно ()
, и поскольку доступно только это значение, компилятор принимает его.
Из документации:
Если ee имеет некоторый тип значения и ожидаемый тип — Unit, ee преобразуется в ожидаемый тип путем встраивания его в терм { ee; () }.
Объекты-одиночки не расширяют AnyVal
, поэтому с ними обращаются по-разному.
Когда вы используете такой синтаксис, как:
new ABC {
// Here comes code that gets executed after the constructor code.
// Code here can returns Unit by default because a constructor always
// returns the type it is constructing.
}
Вы просто добавляете что-то в тело конструктора, вы не передаете параметры.
Второй пример не компилируется, потому что компилятор не может вывести значение по умолчанию для body: => Int
, поэтому вы должны передать его явно.
Вывод
Код внутри скобок для конструктора — это не то же самое, что передача параметра. В одних и тех же случаях это может выглядеть одинаково, но это из-за «волшебства».
person
pedromss
schedule
28.08.2017