Дивно, але всі 10 відповідей тут говорять те саме. '::' - це оператор роздільної здатності простору імен, і так, це правда. Але є одна готча, яку ви повинні усвідомити щодо оператора роздільної здатності простору імен, якщо мова йде про алгоритм постійного пошуку . Як окреслює Мац у своїй книзі "Мова програмування Рубі", постійний пошук має кілька кроків. По-перше, він шукає константу в лексичній області, де посилається на постійну. Якщо вона не знаходить константу в межах лексичної сфери, то вона здійснює пошук ієрархії спадкування . Через цей алгоритм постійного пошуку нижче ми отримуємо очікувані результати:
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