Sorprendentemente, las 10 respuestas aquí dicen lo mismo. El '::' es un operador de resolución de espacio de nombres, y sí, es cierto. Pero hay un problema que debe conocer sobre el operador de resolución de espacio de nombres cuando se trata del algoritmo de búsqueda constante . Como Matz delinea en su libro, 'El lenguaje de programación de Ruby', la búsqueda constante tiene múltiples pasos. Primero, busca una constante en el ámbito léxico donde se hace referencia a la constante. Si no encuentra la constante dentro del alcance léxico, entonces busca en la jerarquía de herencia . Debido a este algoritmo de búsqueda constante, a continuación obtenemos los resultados esperados:
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
Mientras que F hereda de E, el módulo B está dentro del alcance léxico de F. En consecuencia, las instancias F se referirán al PI constante definido en el módulo B. Ahora, si el módulo B no definió PI, entonces las instancias F se referirán al PI constante definida en la superclase E.
Pero, ¿qué pasaría si tuviéramos que usar '::' en lugar de anidar módulos? ¿Conseguiríamos el mismo resultado? ¡No!
Al utilizar el operador de resolución de espacio de nombres al definir módulos anidados, los módulos y clases anidados ya no están dentro del alcance léxico de sus módulos externos. Como puede ver a continuación, el PI definido en A :: B no está en el ámbito léxico de A :: B :: C :: D y, por lo tanto, obtenemos una constante no inicializada al intentar hacer referencia a PI en el método de instancia 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