ruby的双冒号'::'是什么?

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

我找到了一个定义:

::是一个一元操作符,允许在类或模块中定义的常量、实例方法和类方法从类或模块外部的任何地方访问。

如果你只能使用::来暴露任何东西,那么作用域(私有的,受保护的)有什么用呢?

142606 次浏览

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

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

::基本上是一个名称空间解析操作符。它允许您访问模块中的项,或类中的类级项。例如,假设你有这样的设置:

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

你可以从模块外部作为SomeModule::InnerModule::MyClass::CONSTANT访问CONSTANT

它不会影响类中定义的实例方法,因为您可以使用不同的语法(点.)访问这些方法。

相关注意:如果你想回到顶层命名空间,请执行:::SomeModule - 本杰明·奥克斯

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

当你在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

::操作符不允许你绕过标记为private或protected的方法的可见性。

如果你只能使用::来暴露任何东西,那么作用域(私有的,受保护的)有什么用呢?

在Ruby中,所有内容都是公开的,并且可以从其他任何地方修改所有内容。

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

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

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

例如,在第一行中,Rails使用它来查找ActiveRecord内部的基类。模块,在你的第二个模块中,它用于定位路由类的类方法(静态),等等。

它不是用来暴露任何东西,而是用来“定位”你瞄准镜周围的东西。

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

下面这个简单的例子说明了这一点:

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

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定义在users下。

并路由为:

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




class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController


end
module Amimal
module Herbivorous
EATER="plants"
end
end


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

::用于创建作用域。为了从2个模块中访问Constant EATER,我们需要确定模块的范围以达到常数

加上前面的答案,使用::访问实例方法是有效的Ruby。以下均有效:

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

根据最佳实践,我认为只推荐最后一种。

令人惊讶的是,这里的10个答案都说了同样的事情。'::'是一个名称空间解析操作符,是的,它是真的。但是当涉及到常量查找算法时,关于名称空间解析操作符有一个你必须意识到的问题。正如Matz在他的书《Ruby编程语言》中描述的那样,常量查找有多个步骤。首先,它在引用常量的词法作用域中搜索一个常量。如果在词法范围内没有找到常量,则搜索继承层次结构. c。由于这个常量查找算法,我们得到了下面的预期结果:

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

简单来说,它是一个命名空间, 命名空间是模块、类、函数等的容器。同时也有助于解决名称冲突的问题。 在ruby中,你可以通过

这样的模块来访问命名空间
module A
class Article
def Base
end
module B
end
end

所以要访问类Article我们使用A::Article。 在某些情况下你会看到 答::Article<应用程序::Base 这意味着模块A的Article类继承了Application模块的基类

恢复这个线程。 我们可以为这个操作符创建一个ruby名称吗:: 令人惊讶的是,我们还没有,因为我们有splats, spread, hash rockets等

当然我们可以想出比“双冒号”或“一元运算符”更有趣的东西

思考

  • 四点
  • 四眼
  • 利乐点
  • 啃(半字节- 4位)