Überraschenderweise sagen alle 10 Antworten hier dasselbe. Das '::' ist ein Namespace-Auflösungsoperator, und ja, es ist wahr. Es gibt jedoch eine Sache, die Sie über den Namespace-Auflösungsoperator wissen müssen, wenn es um den Algorithmus für die konstante Suche geht . Wie Matz in seinem Buch "The Ruby Programming Language" beschreibt, besteht die ständige Suche aus mehreren Schritten. Zunächst wird eine Konstante im lexikalischen Bereich durchsucht, auf die auf die Konstante verwiesen wird. Wenn die Konstante nicht im lexikalischen Bereich gefunden wird, wird die Vererbungshierarchie durchsucht . Aufgrund dieses konstanten Suchalgorithmus erhalten wir unten die erwarteten Ergebnisse:
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
Während F von E erbt, befindet sich das B-Modul im lexikalischen Bereich von F. Folglich beziehen sich F-Instanzen auf die im Modul B definierte Konstante PI. Wenn Modul B PI nicht definiert hat, beziehen sich F-Instanzen auf den PI Konstante in der Oberklasse E definiert.
Aber was wäre, wenn wir '::' verwenden würden, anstatt Module zu verschachteln? Würden wir das gleiche Ergebnis erzielen? Nein!
Durch die Verwendung des Namespace-Auflösungsoperators beim Definieren verschachtelter Module befinden sich die verschachtelten Module und Klassen nicht mehr im lexikalischen Bereich ihrer äußeren Module. Wie Sie unten sehen können, befindet sich das in A :: B definierte PI nicht im lexikalischen Bereich von A :: B :: C :: D, und daher erhalten wir eine nicht initialisierte Konstante, wenn wir versuchen, in der Instanzmethode get_pi auf PI zu verweisen:
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