Удивительно, но все 10 ответов здесь говорят об одном и том же. '::' является оператором разрешения пространства имен, и да, это правда. Но есть один момент, который вы должны понять, об операторе разрешения пространства имен, когда дело доходит до алгоритма постоянного поиска . Как подчеркивает Мац в своей книге «Язык программирования Ruby», постоянный поиск состоит из нескольких шагов. Во-первых, он ищет константу в лексическом контексте, на которую ссылается константа. Если он не находит константу в лексической области, он ищет иерархию наследования . Из-за этого алгоритма постоянного поиска ниже мы получаем ожидаемые результаты:
module A
module B
PI = 3.14
module C
class E
PI = 3.15
end
class F < E
def get_pi
puts PI
end
end
end
end
end
f = A::B::C::F.new
f.get_pi
> 3.14
Хотя F наследуется от E, модуль B находится в лексической области действия F. Следовательно, экземпляры F будут ссылаться на константу PI, определенную в модуле B. Теперь, если модуль B не определил PI, тогда экземпляры F будут ссылаться на PI. константа, определенная в суперклассе E.
Но что, если бы мы использовали «::» вместо вложенных модулей? Получим ли мы такой же результат? Нет!
При использовании оператора разрешения пространства имен при определении вложенных модулей вложенные модули и классы больше не входят в лексическую область своих внешних модулей. Как вы можете видеть ниже, PI, определенный в A :: B, не входит в лексическую область A :: B :: C :: D, и поэтому мы получаем неинициализированную константу при попытке обратиться к PI в методе экземпляра get_pi:
module A
end
module A::B
PI = 3.14
end
module A::B::C
class D
def get_pi
puts PI
end
end
end
d = A::B::C::D.new
d.get_pi
NameError: uninitialized constant A::B::C::D::PI
Did you mean? A::B::PI