::
是什么?例如,Foo::Bar
。我找到了一个定义:
::是一元操作符,允许从类或模块内定义的常量、实例方法和类方法在类或模块外部被访问。
如果可以使用
::
来公开任何内容,那么范围(私有、受保护)有何用处?::
是什么?例如,Foo::Bar
。::
来公开任何内容,那么范围(私有、受保护)有何用处?::
基本上是一个命名空间解析运算符。它允许您访问模块中的项目,或类中级别的项目。例如,假设您有以下设置:
module SomeModule
module InnerModule
class MyClass
CONSTANT = 4
end
end
end
您可以通过以下方式从模块外部访问CONSTANT
: SomeModule::InnerModule::MyClass::CONSTANT
。
这不影响在类中定义的实例方法,因为您使用不同的语法(点.
)来访问它们。
相关说明:如果您想返回到顶级命名空间,请执行此操作:::SomeModule - Benjamin Oakes。
::
来解决命名空间问题,例如 std::cout << "Hello World!";
。 - Jerry Fernholz::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
::
允许您访问另一个类或模块中定义的常量、模块或类。它用于提供命名空间,以便方法和类名称不会与其他作者创建的类产生冲突。
当您在Rails中看到ActiveRecord::Base
时,意味着Rails具有类似以下结构:
module ActiveRecord
class Base
end
end
即在模块 ActiveRecord
内部有一个名为 Base
的类,可以通过 ActiveRecord::Base
引用它(你可以在 Rails 源码的 activerecord-n.n.n/lib/active_record/base.rb 中找到它)。module Math
PI = 3.141 # ...
end
puts Math::PI
::
运算符不能绕过被标记为私有或受保护的方法的可见性。
class MyClass < ActiveRecord::Base
,那么这意味着MyClass只会继承基础类中的方法,而不会继承ActiveRecord模块中的任何内容吗? - Charlie Parkerclass Foo; Baz = 42; def self.Baz; "Baz method!"; end; end
(完全有效),Foo::Baz # => 42
和 Foo.Baz # => "Baz method!"
。请注意,Foo::Baz()
(带有括号)也会调用该方法。 - mikej如果你可以使用 :: 暴露任何东西,那么作用域(private,protected)有何用处?
在Ruby中,一切都是暴露的,任何地方都可以修改。
如果你担心类可以从“类定义”之外被修改,那么Ruby可能不适合你。
另一方面,如果你对Java的类被锁定感到沮丧,那么Ruby可能是你要找的。
attr_accessor
只是创建修改变量的方法。(当然还有 instance_eval
) - Andrew Grimminstance_eval
方法。但也有instance_variable_get
和instance_variable_set
方法。Ruby太过动态以致于无法限制。 - yfeldblum出人意料的是,这里的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
在之前的回答中,提到了可以使用::
来访问实例方法。以下所有方式都是有效的:
MyClass::new::instance_method
MyClass::new.instance_method
MyClass.new::instance_method
MyClass.new.instance_method
根据最佳实践,我认为只有最后一个被推荐。
::
进行命名空间解析。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"
::用于创建作用域。为了从两个模块访问常量EATER,我们需要将模块的作用域限定到常量所在的范围。