什么是Ruby的双冒号`::`?

时间:2010-06-09 20:03:36

标签: ruby syntax operators

这个双冒号::是什么?例如。 Foo::Bar

我找到了definition

  

::是一元运算符,允许:从类或模块外的任何位置访问类或模块中定义的常量,实例方法和类方法。

如果您可以使用::公开任何内容,那么范围(私有,受保护)有什么用处?

10 个答案:

答案 0 :(得分:350)

::基本上是命名空间解析运算符。它允许您访问模块中的项目或类中的类级别项目。例如,假设你有这个设置:

module SomeModule
    module InnerModule
        class MyClass
            CONSTANT = 4
        end
    end
end

您可以通过CONSTANT从模块外部访问SomeModule::InnerModule::MyClass::CONSTANT

它不会影响在类上定义的实例方法,因为您可以访问具有不同语法的那些(点.)。

相关说明:如果要返回顶级命名空间,请执行以下操作::: SomeModule - Benjamin Oakes

答案 1 :(得分:103)

这个简单的例子说明了它:

MR_COUNT = 0        # constant defined on main Object class
module Foo
  MR_COUNT = 0
  ::MR_COUNT = 1    # set global count to 1
  MR_COUNT = 2      # set local count to 2
end

puts MR_COUNT       # this is the global constant
puts Foo::MR_COUNT  # this is the local "Foo" constant

取自http://www.tutorialspoint.com/ruby/ruby_operators.htm

答案 2 :(得分:70)

::允许您访问在另一个类或模块中定义的常量,模块或类。它用于提供名称空间,以便方法和类名称不会与不同作者的其他类冲突。

当你在Rails中看到ActiveRecord::Base时,它意味着Rails有类似

的东西
module ActiveRecord
  class Base
  end
end

即。模块Base中名为ActiveRecord的类,然后引用为ActiveRecord::Base(您可以在activerecord -nnn / lib / active_record / base.rb的Rails源代码中找到它)

::的一个常见用途是访问模块中定义的常量,例如

module Math
  PI = 3.141 # ...
end

puts Math::PI

::运算符不允许您绕过标记为private或protected的方法的可见性。

答案 3 :(得分:23)

  

如果你可以使用::来暴露任何东西,那么范围(私有,受保护)有什么用呢?

在Ruby中,一切都暴露出来,一切都可以从其他地方修改。

如果您担心可以从“类定义”之外更改类,那么Ruby可能不适合您。

另一方面,如果你对Java的类被锁定感到沮丧,那么Ruby可能就是你正在寻找的。

答案 4 :(得分:11)

不,它不是访问每个方法,它是一个“解析”操作符,也就是说,你用它来解析常量/静态符号的范围(或你可以说的位置)。

例如,在你的第一行中,Rails使用它来查找ActiveRecord.Module中的Base类,在第二行中它用于定位Routes类的类方法(静态)等。

它不用于暴露任何东西,它用于“定位”你的范围内的东西。

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

答案 5 :(得分:8)

添加到以前的答案,使用::访问实例方法是有效的Ruby。以下所有内容均有效:

MyClass::new::instance_method
MyClass::new.instance_method
MyClass.new::instance_method
MyClass.new.instance_method

根据最佳做法,我认为只推荐最后一个。

答案 6 :(得分:4)

所有这些都是为了防止定义与链接到项目中的其他代码发生冲突。这意味着你可以把事情分开。

例如,您可以在代码中使用一个名为“run”的方法,您仍然可以调用您的方法,而不是在已链接的其他库中定义的“run”方法。

答案 7 :(得分:3)

Ruby on rails使用:: for namespace resolution。

class User < ActiveRecord::Base

  VIDES_COUNT = 10
  Languages = { "English" => "en", "Spanish" => "es", "Mandarin Chinese" => "cn"}

end

使用它:

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

此外,其他用法是:使用嵌套路线时

OmniauthCallbacksController在用户下定义。

和路线就像:

devise_for :users, controllers: {omniauth_callbacks: "users/omniauth_callbacks"}


class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

end

答案 8 :(得分:2)

module Amimal
      module Herbivorous
            EATER="plants" 
      end
end

Amimal::Herbivorous::EATER => "plants"

::用于创建范围。为了从2个模块访问Constant EATER,我们需要将模块的范围扩展到常量

答案 9 :(得分:2)

令人惊讶的是,这里的所有10个答案都说相同的话。 '::'是名称空间解析运算符,是的。但是,当涉及到恒定查找算法时,您必须意识到名称空间解析运算符。正如Matz在他的《 Ruby编程语言》一书中所描述的那样,持续查找有多个步骤。首先,它在引用该常量的词法范围中搜索一个常量。如果找不到词法范围内的常量,则搜索继承层次。由于采用了这种恒定查找算法,因此我们可以得到以下预期结果:

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

虽然F继承自E,但是B模块在F的词法范围内。因此,F实例将引用模块B中定义的常量PI。现在,如果模块B未定义PI,则F实例将引用到超类E中定义的PI常量。

但是如果我们使用'::'而不是嵌套模块怎么办?我们会得到相同的结果吗?不!

通过在定义嵌套模块时使用名称空间解析运算符,嵌套模块和类不再位于其外部模块的词法范围内。如下所示,A :: B中定义的PI不在A :: B :: C :: D的词法范围内,因此当尝试在get_pi实例方法中引用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