Я хорошо знаком с тем, когда использовать подклассы и модули, но совсем недавно я видел такие вложенные классы:
class Foo
class Bar
# do some useful things
end
end
А также классы, вложенные в такие модули:
module Baz
class Quux
# more code
end
end
Либо документация и статьи немногочисленны, либо я недостаточно осведомлен по этому вопросу, чтобы нащупать правильные условия поиска, но, похоже, я не могу найти много информации по теме.
Может ли кто-нибудь предоставить примеры или ссылки на сообщения о том, почему и когда будут использоваться эти методы?
Car.new
иCar::Wheel.new
. Вам определенно не нужно инициализироватьCar
объект для инициализацииCar::Wheel
объекта в Ruby, ноCar
класс должен быть загружен и выполнен,Car::Wheel
чтобы его можно было использовать.Car
иCar::Wheel
. Модули (и, следовательно, классы) - это просто пространства имен для констант, в Ruby нет таких вещей, как вложенный класс или вложенный модуль.Car::Wheel.new
. Бум. Я только что построилWheel
объект, который не вложен вCar
объект.В Ruby определение вложенного класса похоже на определение класса в модуле. На самом деле он не вызывает ассоциации между классами, он просто создает пространство имен для констант. (Имена классов и модулей являются константами.)
Принятый ответ ни в чем не был правильным. В приведенном ниже примере я создаю экземпляр лексически замкнутого класса без когда-либо существовавшего экземпляра включающего класса.
class A; class B; end; end A::B.new
Преимущества те же, что и для модулей: инкапсуляция, группировка кода, используемого только в одном месте, и размещение кода ближе к тому месту, где он используется. В большом проекте может быть один внешний модуль, который повторяется снова и снова в каждом исходном файле и содержит множество определений классов. Когда все различные фреймворки и библиотечные коды делают это, тогда они вносят только одно имя на верхний уровень, уменьшая вероятность конфликтов. Прозаика, конечно, но они поэтому и используются.
Использование класса вместо модуля для определения внешнего пространства имен может иметь смысл в однофайловой программе или скрипте, или если вы уже используете для чего-то класс верхнего уровня, или если вы действительно собираетесь добавить код для связывания классов вместе в истинном стиле внутреннего класса . Ruby не имеет внутренних классов, но ничто не мешает вам создать примерно такое же поведение в коде. Ссылка на внешние объекты из внутренних по-прежнему потребует расставления точек в экземпляре внешнего объекта, но вложенность классов предполагает, что это то, что вы могли бы делать. Тщательно модульная программа всегда может сначала создавать включающие классы, и их можно разумно разложить на вложенные или внутренние классы. Вы не можете вызвать
new
модуль.Вы можете использовать общий шаблон даже для сценариев, где пространство имен не очень необходимо, просто для развлечения и практики ...
#!/usr/bin/env ruby class A class Realwork_A ... end class Realwork_B ... end def run ... end self end.new.run
источник
B
находится внутри класса . Константа в пространстве имен внутри класса , но нет абсолютно никакой связи между объектом , на который ссылается (в данном случае как раз случается быть класс) и класса , на который ссылается .A
B
A
B
A
You can't call new on a module.
- так что в общих чертах, если я просто хочу создать пространство имен для некоторых классов и мне никогда не нужно создавать экземпляр внешнего «класса», тогда Я бы использовал внешний модуль. Но если я хочу создать экземпляр обертывающего / внешнего «класса», я бы сделал его классом, а не модулем. По крайней мере, для меня это имеет смысл.Вероятно, вы захотите использовать это, чтобы сгруппировать свои классы в модуль. Что-то вроде пространства имен.
например, гем Twitter использует для этого пространства имен:
Так что оба класса
Client
иSearch
находятся подTwitter
модулем.Если вы хотите проверить исходники, код для обоих классов можно найти здесь и здесь .
Надеюсь это поможет!
источник
Есть еще одно различие между вложенными классами и вложенными модулями в Ruby до версии 2.5, которую другие ответы не смогли охватить, и я считаю, что здесь следует упомянуть. Это процесс поиска.
Вкратце: из-за поиска констант верхнего уровня в Ruby до версии 2.5 Ruby может в конечном итоге искать ваш вложенный класс в неправильном месте (
Object
в частности), если вы используете вложенные классы.В Ruby до версии 2.5:
Структура
X
вложенного класса : предположим, у вас есть класс с вложенным классомY
илиX::Y
. И тогда у вас также есть класс верхнего уровня с именемY
. ЕслиX::Y
не загружен, то при вызове происходит следующееX::Y
:Не найдя
Y
вX
, Ruby попытается найти его в предкахX
. посколькуX
это класс, а не модуль, у него есть предки, среди которых есть[Object, Kernel, BasicObject]
. Таким образом, он пытается искатьY
инObject
, где он находит его успешно.Все же это верхний уровень
Y
и нетX::Y
. Вы получите это предупреждение:warning: toplevel constant Y referenced by X::Y
Структура вложенного модуля: предположим, что в предыдущем примере
X
это модуль, а не класс.Модуль имеет только самого себя в качестве предка:
X.ancestors
будет производить[X]
.В этом случае Ruby не сможет искать
Y
в одном из предковX
и выбросит файлNameError
.X::Y
После этого Rails (или любой другой фреймворк с автозагрузкой) попытается загрузиться .См. Эту статью для получения дополнительной информации: https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/
В Ruby 2.5:
удален поиск констант верхнего уровня.
Вы можете использовать вложенные классы, не опасаясь столкнуться с этой ошибкой.
источник
В дополнение к предыдущим ответам: модуль в Ruby - это класс
$ irb > module Some end => nil > Some.class => Module > Module.superclass => Object
источник
new
. Итак, хотя вы можете сказать, что модули - это класс (нижний регистр), это не то же самое, что класс (верхний регистр) :)