Удивительно, но все 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