这个双冒号 ::
是什么?例如Foo::Bar
。
我找到了一个 definition:
:: 是一个一元运算符,它允许:在类或模块中定义的常量、实例方法和类方法,可以从类或模块之外的任何地方访问。
如果您可以使用 ::
公开任何内容,那么范围(私有、受保护)有什么用?
::
基本上是一个命名空间解析运算符。它允许您访问模块中的项目,或类中的类级项目。例如,假设您有以下设置:
module SomeModule
module InnerModule
class MyClass
CONSTANT = 4
end
end
end
您可以作为 SomeModule::InnerModule::MyClass::CONSTANT
从模块外部访问 CONSTANT
。
它不会影响在类上定义的实例方法,因为您使用不同的语法(点 .
)访问那些实例方法。
相关说明:如果要返回顶级命名空间,请执行以下操作:::SomeModule – Benjamin Oakes
这个简单的例子说明了这一点:
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: 1
puts Foo::MR_COUNT # this is the local constant: 2
取自 http://www.tutorialspoint.com/ruby/ruby_operators.htm
::
允许您访问在另一个类或模块中定义的常量、模块或类。它用于提供命名空间,以便方法和类名不会与不同作者的其他类冲突。
当您在 Rails 中看到 ActiveRecord::Base
时,这意味着 Rails 有类似的东西
module ActiveRecord
class Base
end
end
即在模块 ActiveRecord
中称为 Base
的类,然后将其引用为 ActiveRecord::Base
(您可以在 Rails 源代码中的 activerecord-nnn/lib/active_record/base.rb 中找到它)
:: 的一个常见用途是访问模块中定义的常量,例如
module Math
PI = 3.141 # ...
end
puts Math::PI
::
运算符不允许您绕过标记为私有或受保护的方法的可见性。
class MyClass < ActiveRecord::Base
,这是否意味着 MyClass 只继承类基的方法,而不是 ActiveRecord 模块中的任何东西?
class Foo; Baz = 42; def self.Baz; "Baz method!"; end; end
(完全有效)Foo::Baz # => 42
和 Foo.Baz # => "Baz method!"
。请注意,Foo::Baz()
(带括号)也会调用该方法。
如果您可以使用 :: 来公开任何内容,那么范围(私有、受保护)有什么好处?
在 Ruby 中,一切都是公开的,一切都可以从其他任何地方进行修改。
如果您担心可以从“类定义”之外更改类这一事实,那么 Ruby 可能不适合您。
另一方面,如果您对 Java 的类被锁定感到沮丧,那么 Ruby 可能就是您正在寻找的。
attr_accessor
也只是创建了修改变量的方法。 (然后又是 instance_eval
)
instance_eval
。但也有 instance_variable_get
和 instance_variable_set
。 Ruby 对于约束来说太动态了。
添加到以前的答案中,使用 ::
访问实例方法是有效的 Ruby。以下所有内容均有效:
MyClass::new::instance_method
MyClass::new.instance_method
MyClass.new::instance_method
MyClass.new.instance_method
根据最佳实践,我相信只推荐最后一个。
令人惊讶的是,这里的所有 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 实例将引用 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
不,它不是访问每个方法,它是一个“解析”运算符,也就是说,您使用它来解析常量/静态符号的范围(或您可以说的位置)。
例如,在您的第一行中,Rails 使用它来查找 ActiveRecord.Module 中的 Base 类,在您的第二行中,它用于定位 Routes 类的类方法(静态)等。
它不用于暴露任何东西,它用于“定位”范围内的东西。
http://en.wikipedia.org/wiki/Scope_resolution_operator
Ruby on rails 使用 ::
进行命名空间解析。
class User < ActiveRecord::Base
VIDEOS_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
这一切都是为了防止定义与链接到您的项目的其他代码发生冲突。这意味着您可以将事物分开。
例如,您可以在代码中使用一种名为“run”的方法,并且您仍然可以调用您的方法,而不是在您链接的其他库中定义的“run”方法。
module Amimal
module Herbivorous
EATER="plants"
end
end
Amimal::Herbivorous::EATER => "plants"
:: 用于创建范围。为了从 2 个模块访问常量 EATER,我们需要对模块进行范围以达到常量
简单来说它是一个命名空间,现在命名空间是模块、类、函数等的容器。它还有助于解决问题名称冲突。在 ruby 中,您可以按模块访问命名空间,例如
module A
class Article
def Base
end
module B
end
end
所以要访问文章类,我们使用 A::Article。在某些情况下,您会看到 A::Article
稍微恢复一下这个线程。我们可以为这个操作员创建一个“红宝石”名称吗 :: 很惊讶我们还没有,因为我们有 splats、spreads、hash rockets 等。
当然,我们可以想出比“双冒号”或“一元运算符”更有趣的东西
思维
四点
四眼
四点
半字节(半个字节 - 4 位)
::
进行命名空间解析,例如std::cout << "Hello World!";
::SomeModule