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

后端 未结 10 1989
南笙
南笙 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 10:47

    No, it is not to access every method, it is a "resolution" operator, that is, you use it to resolve the scope (or location you can say) of a constant/static symbol.

    For example in the first of your line, Rails use it to find the Base class inside the ActiveRecord.Module, in your second one it is used to locate the class method (static) of the Routes class, etc, etc.

    It is not used to expose anything, its used to "locate" stuff around your scopes.

    http://en.wikipedia.org/wiki/Scope_resolution_operator

    0 讨论(0)
  • 2020-11-22 10:51

    Ruby on rails uses :: for namespace resolution.

    class User < ActiveRecord::Base
    
      VIDEOS_COUNT = 10
      Languages = { "English" => "en", "Spanish" => "es", "Mandarin Chinese" => "cn"}
    
    end
    

    To use it :

    User::VIDEOS_COUNT
    User::Languages
    User::Languages.values_at("Spanish") => "en"
    

    Also, other usage is : When using nested routes

    OmniauthCallbacksController is defined under users.

    And routed as:

    devise_for :users, controllers: {omniauth_callbacks: "users/omniauth_callbacks"}
    
    
    class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
    
    end
    
    0 讨论(0)
  • 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
    
    0 讨论(0)
  • 2020-11-22 11:01

    It is all about preventing definitions from clashing with other code linked in to your project. It means you can keep things separate.

    For example you can have one method called "run" in your code and you will still be able to call your method rather than the "run" method that has been defined in some other library that you have linked in.

    0 讨论(0)
提交回复
热议问题