What is Ruby's double-colon `::`?

后端 未结 10 2119
南笙
南笙 2020-11-22 10:09

What is this double-colon ::? E.g. Foo::Bar.

I found a definition:

The :: is a unary operator that all

10条回答
  •  轮回少年
    2020-11-22 11:00

    Surprisingly, all 10 answers here say the same thing. The '::' is a namespace resolution operator, and yes it is true. But there is one gotcha that you have to realize about the namespace resolution operator when it comes to the constant lookup algorithm. As Matz delineates in his book, 'The Ruby Programming Language', constant lookup has multiple steps. First, it searches a constant in the lexical scope where the constant is referenced. If it does not find the constant within the lexical scope, it then searches the inheritance hierarchy. Because of this constant lookup algorithm, below we get the expected results:

    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
    

    While F inherits from E, the B module is within the lexical scope of F. Consequently, F instances will refer to the constant PI defined in the module B. Now if module B did not define PI, then F instances will refer to the PI constant defined in the superclass E.

    But what if we were to use '::' rather than nesting modules? Would we get the same result? No!

    By using the namespace resolution operator when defining nested modules, the nested modules and classes are no longer within the lexical scope of their outer modules. As you can see below, PI defined in A::B is not in the lexical scope of A::B::C::D and thus we get uninitialized constant when trying to refer to PI in the get_pi instance method:

    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
    

提交回复
热议问题