O dziwo, wszystkie 10 odpowiedzi tutaj mówią to samo. „::” jest operatorem rozpoznawania przestrzeni nazw i tak, to prawda. Ale jest jeden problem, który musisz wiedzieć o operatorze rozpoznawania przestrzeni nazw, jeśli chodzi o algorytm ciągłego wyszukiwania . Jak opisuje Matz w swojej książce „The Ruby Programming Language”, ciągłe wyszukiwanie ma wiele kroków. Po pierwsze, przeszukuje stałą w zakresie leksykalnym, do którego odwołuje się stała. Jeśli nie znajdzie stałej w zakresie leksykalnym, przeszukuje hierarchię dziedziczenia . Z powodu tego algorytmu ciągłego wyszukiwania poniżej otrzymujemy oczekiwane wyniki:
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
Podczas gdy F dziedziczy z E, moduł B mieści się w zakresie leksykalnym F. W związku z tym instancje F będą odnosić się do stałej PI zdefiniowanej w module B. Teraz, jeśli moduł B nie zdefiniował PI, wówczas instancje F będą odnosić się do PI stała zdefiniowana w nadklasie E.
Ale co, jeśli użyjemy „::” zamiast zagnieżdżać moduły? Czy uzyskalibyśmy ten sam wynik? Nie!
Dzięki zastosowaniu operatora rozpoznawania przestrzeni nazw podczas definiowania zagnieżdżonych modułów, zagnieżdżone moduły i klasy nie są już objęte zakresem leksykalnym ich zewnętrznych modułów. Jak widać poniżej, PI zdefiniowane w A :: B nie znajduje się w zakresie leksykalnym A :: B :: C :: D i dlatego otrzymujemy niezainicjowaną stałą podczas próby odwołania się do PI w metodzie instancji 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