Подтвердить что ты не робот

Почему люди определяют класс, черту, объект внутри другого объекта в Scala?

Хорошо, я объясню, почему я задаю этот вопрос. В эти дни я начинаю читать исходный код версии 2.2. Хорошо, если раньше вам приходилось читать исходный код для подъема.

В Lift я обнаружил, что определение внутреннего класса и внутреннего признака очень сильно используется.

объект Menu имеет 2 внутренних свойства и 4 внутренних класса. объект Loc имеет 18 внутренних классов, 5 внутренних признаков, 7 внутренних объектов.

Там написано много кодов. Я хочу знать, почему автор пишет вот так.

  • Это потому, что это авторский личный вкус или мощное использование языковая функция?
  • Есть ли какие-либо компромиссы для такого рода использования?
4b9b3361

Ответ 1

До 2.8 вам пришлось выбирать между пакетами и объектами. Проблема с пакетами заключается в том, что они не могут содержать методы или валы самостоятельно. Поэтому вы должны поместить всех тех, кто находится внутри другого объекта, что может стать неудобным. Обратите внимание:

object Encrypt {
  private val magicConstant = 0x12345678
  def encryptInt(i: Int) = i ^ magicConstant
  class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
    def hasNext = ii.hasNext
    def next = encryptInt(ii.next)
  }
}

Теперь вы можете import Encrypt._ и получить доступ к методу encryptInt, а также классу EncryptIterator. Handy!

Напротив,

package encrypt {
  object Encrypt {
    private[encrypt] val magicConstant = 0x12345678
    def encryptInt(i: Int) = i ^ magicConstant
  }
  class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
    def hasNext = ii.hasNext
    def next = Encrypt.encryptInt(ii.next)
  }
}

Это не огромная разница, но он заставляет пользователя импортировать как encrypt._, так и encrypt.Encrypt._ или продолжать писать Encrypt.encryptInt снова и снова. Почему бы просто не использовать объект, как в первом шаблоне? (На самом деле нет штрафа за производительность, поскольку вложенные классы на самом деле не являются внутренними классами Java под капотом, они просто обычные классы, насколько известно JVM, но с причудливыми именами, которые говорят вам, что они вложены.)

В 2.8 вы можете получить свой торт и съесть его тоже: назовите вещь объектом пакета, а компилятор перепишет код для вас, так что он на самом деле выглядит как второй пример под капотом (кроме объекта Encrypt на самом деле называется package внутренне), но ведет себя как первый пример в терминах пространства имен - vals и defs находятся прямо там, не требуя дополнительного импорта.

Таким образом, проекты, которые были запущены до 2.8, часто используют объекты, чтобы вложить много вещей, как если бы они были пакетом. После 2.8, одна из главных мотивов была удалена. (Но для того, чтобы быть ясным, использование объекта все равно не повредит, тем более, что он концептуально вводит в заблуждение, чем то, что он отрицательно влияет на производительность или что-то еще.)

(P.S. Пожалуйста, не пытайтесь на самом деле шифровать что-либо, кроме как в качестве примера или шутки!)

Ответ 2

Это может быть и то, и другое. Среди прочего, экземпляр внутреннего класса/свойства имеет доступ к переменным его родителя. Внутренние классы должны быть созданы с родительским экземпляром, который является экземпляром внешнего типа.

В других случаях это, вероятно, просто способ группировки тесно связанных вещей, как в вашем примере object. Обратите внимание, что символ LocParam запечатан, что означает, что все подклассы должны находиться в одном компиляторе/файле.

Ответ 4

sblundy имеет достойный ответ. Добавим, что только с Scala 2.8 у вас есть объекты пакета, которые позволяют группировать подобные вещи в пространстве имен пакетов без создания полностью отдельного объекта. По этой причине я буду обновлять предложение Lift Modules для использования объекта пакета вместо простого объекта.