ChatGPT解决这个技术问题 Extra ChatGPT

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

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

我找到了一个 definition

:: 是一个一元运算符,它允许:在类或模块中定义的常量、实例方法和类方法,可以从类或模块之外的任何地方访问。

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

为了将来的 Google 员工的利益,如果您要搜索符号,请尝试 symbolhound.com
祝福你,@AndrewGrimm。这是我这周看到的最好的东西。

D
Derrell Durrett

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

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

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

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

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


例如,在 C# 中,是的。另一方面,C++(和 Ruby)使用 :: 进行命名空间解析,例如 std::cout << "Hello World!";
相关说明:如果要返回顶级命名空间,请执行以下操作:::SomeModule
@Benjamin 前导冒号是隐含的,除非我碰巧在另一个模块中有一个 SomeModule 并且我想获得顶级的,对吗?
@乔是的。如果您想确保引用顶级命名空间中的常量或另一个模块中具有相同名称的常量(例如 ::SomeOtherModule::ClassMethods),这将很有帮助。
这很像 C++ 的作用域操作数
d
dimpiax

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

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


这就是导致警告的原因。有没有办法逃避警告?
@NullVoxPopuli 通常修改常量是一件非常糟糕的事情,但如果你想修改一个写得不好的 gem 中的常量并且不想分叉它,可以通过使用 .send(:remove_const) 到定义它的模块来完成,然后重新定义常数。
m
mikej

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

当您在 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 模块中的任何东西?
为什么要为这个命名空间解析使用特殊的双冒号而不是使用“.”也是为了这个?即使我们使用“.”,上下文和大写也可以防止含义混淆,不是吗?
@Jonah 在某些情况下会模棱两可。例如,考虑 class Foo; Baz = 42; def self.Baz; "Baz method!"; end; end(完全有效)Foo::Baz # => 42Foo.Baz # => "Baz method!"。请注意,Foo::Baz()(带括号)也会调用该方法。
那么用例它解决了具有类常量和具有完全相同名称的类方法的能力?这似乎不是支持该功能的有力论据。就个人而言,我宁愿失去这种能力(无论如何似乎很麻烦),失去双冒号,并使用“。”也用于命名空间......也许它解决了其他用例?
y
yfeldblum

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

在 Ruby 中,一切都是公开的,一切都可以从其他任何地方进行修改。

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

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


我听说一些 rubyists 说实例变量没有公开,甚至 attr_accessor 也只是创建了修改变量的方法。 (然后又是 instance_eval
正确,有 instance_eval。但也有 instance_variable_getinstance_variable_set。 Ruby 对于约束来说太动态了。
Y
Yuri Ghensev

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

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

根据最佳实践,我相信只推荐最后一个。


D
Daniel Viglione

令人惊讶的是,这里的所有 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

这应该按答案的顺序更高。
F
Francisco Soto

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

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

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

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


“(静态)”是指“(绘制)”吗?!?
M
Mefitico

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

M
Mongus Pong

这一切都是为了防止定义与链接到您的项目的其他代码发生冲突。这意味着您可以将事物分开。

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


F
Francesca Rodricks
module Amimal
      module Herbivorous
            EATER="plants" 
      end
end

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

:: 用于创建范围。为了从 2 个模块访问常量 EATER,我们需要对模块进行范围以达到常量


A
Aaquib Jawed

简单来说它是一个命名空间,现在命名空间是模块、类、函数等的容器。它还有助于解决问题名称冲突。在 ruby 中,您可以按模块访问命名空间,例如

module A
  class Article
     def Base
     end
  module B
  end
end

所以要访问文章类,我们使用 A::Article。在某些情况下,您会看到 A::Article


b
bubbaspaarx

稍微恢复一下这个线程。我们可以为这个操作员创建一个“红宝石”名称吗 :: 很惊讶我们还没有,因为我们有 splats、spreads、hash rockets 等。

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

思维

四点

四眼

四点

半字节(半个字节 - 4 位)