В Ruby модули и классы являются экземплярами классов Module
и Class
соответственно. Они получают свои имена из константы , которой они назначены. Когда вы пишете:
class A::B
# ...
end
Вы эффективно пишете:
A::B ||= Class.new do
# ...
end
Это допустимый синтаксис присвоения констант, и предполагает , что константа A
правильно инициализирована и , что она ссылается на Module
или Class
.
Например, рассмотрим, как обычно определяются классы:
class A
# ...
end
То, что эффективно происходит, таково:
Object::A ||= Class.new do
# ...
end
Теперь, когда вы пишете:
class A
class B
# ...
end
end
То, что происходит на самом деле, выглядит следующим образом:
(Object::A ||= Class.new).class_eval do
(A::B ||= Class.new).class_eval do
# ...
end
end
Вот что происходит, по порядку:
- Новый экземпляр
Class
назначается константе A
, равной Object
, если только он не был инициализирован.
- Новый экземпляр
Class
присваивается константе B
, равной A
, если только он не был инициализирован.
Это обеспечивает существование всех внешних классов перед попыткой определить любых внутренних классов.
Существует также изменение в области действия, которое позволяет вам напрямую обращаться к константам A
. Сравните:
class A
MESSAGE = "I'm here!"
end
# Scope of Object
class A::B
# Scope of B
puts MESSAGE # NameError: uninitialized constant A::B::MESSAGE
end
# Scope of Object
class A
# Scope of A
class B
# Scope of B
puts MESSAGE # I'm here!
end
end
Согласно этой записи в блоге , основная команда Ruby называет "текущий класс" cref
. К сожалению, автор не уточняет, но, как он отмечает, это отдельно от контекста self
.
Как объяснено здесь , cref
представляет собой связанный список , который представляет собой вложение модулей в некоторый момент времени.
Текущий cref
используется для поиска констант и переменных класса и
для def
, undef
и alias
.
Как уже говорили другие, это разные способы выразить одно и то же.
Однако есть небольшая разница. Когда вы пишете class A::B
, вы предполагаете , что класс A
уже определен. Если этого не произошло, вы получите NameError
, а B
не будет определен вообще.
Написание правильно вложенных модулей:
class A
class B
end
end
Гарантирует, что класс A
существует, прежде чем пытаться определить B
.