В чем разница между классом с сопутствующим объектом и классом и объектом с одинаковым именем?

"Сопутствующий объект" класса Scala можно рассматривать как одноэлементный объект с тем же полностью определенным именем, что и у класса (то есть с тем же именем в том же пакете). Они используются для хранения служебных функций, общих для всех экземпляров класса, в качестве замены для Java static методы.

Однако в разных местах в документах и ​​в вопросах говорится, что сопутствующие объекты должны быть определены в одной и той же единице компиляции. Например, они должны быть определены в одном файле; сопутствующие объекты не могут быть определены для объектов Java; в REPL они должны быть определены в одной строке ввода, отсюда и предупреждающее сообщение:

warning: previously defined class Foo is not a companion to object Foo.
Companions must be defined together; you may wish to use :paste mode for this.

Это подразумевает, что должно быть различие между классом с его сопутствующим объектом и просто классом и объектом с тем же (полностью определенным) именем. Что это за различие?

1 ответ

Решение

Давайте назовем класс class SomeClass (хотя это также может быть, например, trait).

Частные участники

Методы сопутствующего объекта (object SomeClass) иметь доступ к закрытым методам / данным экземпляров class SomeClass,

Если ваш сопутствующий объект использует только открытый интерфейс вашего класса (например, просто определяет константы), практической разницы нет. Но в ряде случаев полезно разрешить служебным функциям получать доступ к закрытым членам. Например, object SomeClass может определить фабричный метод apply который устанавливает частных членов class SomeClass, без необходимости выставлять сеттеры в общедоступном интерфейсе. Поэтому в таких случаях вы должны определить сопутствующий объект, поместив определение object SomeClass в том же модуле компиляции, что и class SomeClass,

Другое отличие состоит в том, что компилятор ищет импликации в сопутствующих объектах типа (и его супертипах). Так что, если вы используете неявные преобразования, вы определяете в коде class SomeClassВы должны определить их в сопутствующем объекте.

Комментарии

Комбинация этих двух также объясняет ограничение для одной и той же единицы компиляции.

  • scalac не может скомпилировать object SomeClass пока он не знает, что частные члены class SomeClass это звонки.
  • scalac не может скомпилировать class SomeClass пока он не знает, что подразумевает, он называет. Таким образом, объект-компаньон должен быть скомпилирован не позднее, чем class SomeClass,

Следовательно, они должны быть скомпилированы одновременно. Кроме того, текущий компилятор, по-видимому, компилирует отдельные файлы отдельно (см. Отсутствие поддержки разделения классов по нескольким файлам), ограничивая его одним и тем же модулем компиляции.

Другие вопросы по тегам