什么是这个双结肠::
?例如。 Foo::Bar
。
我发现了一个definition:
::
是一元运算符,允许:从类或模块外的任何位置访问类或模块中定义的常量,实例方法和类方法。
如果您可以使用::
来暴露任何东西,范围(私人,受保护)有什么用?
::
基本上是命名空间解析运算符。它允许您访问模块中的项目或类中的类级别项目。例如,假设你有这个设置:
module SomeModule
module InnerModule
class MyClass
CONSTANT = 4
end
end
end
您可以从模块外部访问CONSTANT
作为SomeModule::InnerModule::MyClass::CONSTANT
。
它不会影响在类上定义的实例方法,因为您可以访问具有不同语法的那些(点.
)。
相关说明:如果要返回顶级命名空间,请执行以下操作::: SomeModule - Benjamin Oakes
module Amimal
module Herbivorous
EATER="plants"
end
end
Amimal::Herbivorous::EATER => "plants"
::用于创建范围。为了从2个模块访问Constant EATER,我们需要将模块的范围扩展到常量
这个简单的例子说明了它:
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
::
允许您访问在另一个类或模块中定义的常量,模块或类。它用于提供名称空间,以便方法和类名称不会与不同作者的其他类冲突。
当你在Rails中看到ActiveRecord::Base
时,它意味着Rails有类似的东西
module ActiveRecord
class Base
end
end
即一个名为Base
的类,它在ActiveRecord
模块中,然后被引用为ActiveRecord::Base
(你可以在activerecord-n.n.n / lib / active_record / base.rb的Rails源代码中找到它)
::的常见用途是访问模块中定义的常量,例如:
module Math
PI = 3.141 # ...
end
puts Math::PI
::
运算符不允许您绕过标记为private或protected的方法的可见性。
如果您可以使用::来暴露任何东西,那么范围(私有,受保护)有什么用?
在Ruby中,一切都暴露出来,一切都可以从其他地方修改。
如果您担心可以从“类定义”之外更改类,那么Ruby可能不适合您。
另一方面,如果您对Java的类被锁定感到沮丧,那么Ruby可能就是您正在寻找的。
不,它不是访问每个方法,它是一个“分辨率”运算符,也就是说,您使用它来解析常量/静态符号的范围(或您可以说的位置)。
例如,在你的第一行中,Rails使用它来查找ActiveRecord.Module中的Base类,在第二行中它用于定位Routes类的类方法(静态)等。
它不用于暴露任何东西,它用于“定位”你的范围内的东西。
添加到以前的答案,使用::
访问实例方法是有效的Ruby。以下所有内容均有效:
MyClass::new::instance_method
MyClass::new.instance_method
MyClass.new::instance_method
MyClass.new.instance_method
根据最佳实践,我认为只推荐最后一个。
这一切都是为了防止定义与链接到项目中的其他代码发生冲突。这意味着你可以把事情分开。
例如,您可以在代码中使用一个名为“run”的方法,您仍然可以调用您的方法,而不是在已链接的其他库中定义的“run”方法。
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
令人惊讶的是,这里的所有10个答案都说同样的事情。 '::'是命名空间解析运算符,是的,它是真的。但是,当涉及到常量查找算法时,您必须了解名称空间分辨率运算符。正如Matz在他的书“The Ruby Programming Language”中描述的那样,常量查找有多个步骤。首先,它搜索引用常量的词法范围中的常量。如果它没有在词法范围内找到常量,那么它将搜索继承层次结构。由于这种常量查找算法,下面我们得到预期的结果:
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实例将引用PI在超类E中定义的常量
但是,如果我们使用'::'而不是嵌套模块呢?我们会得到相同的结果吗?没有!
通过在定义嵌套模块时使用命名空间解析运算符,嵌套模块和类不再位于其外部模块的词法范围内。如下所示,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