什么时候需要在 Ruby 常量前添加“::”前缀?(未初始化的常量错误)

Ori*_*all 2 ruby inheritance ruby-on-rails constants autoload

错误类似于NameError: uninitialized constant Foo::Bar(whenBar不是 的后代Foo)。

我知道它与加载(自动加载?)常量有关,并且我觉得其中的任何内容都lib/可以安全地不加前缀,::因为它是自动加载的(或其他东西)。

刚刚发生在我身上的一个例子是这样的:

应用程序/资产/类/base_class.rb

class BaseClass
end
Run Code Online (Sandbox Code Playgroud)

应用程序/资产/some_module/some_class.rb

module SomeModule
  class SomeClass < BaseClass
  end
end
Run Code Online (Sandbox Code Playgroud)

我正在运行规范并收到“加载[文件]时发生错误”:NameError: uninitialized constant SomeModule::SomeClass::BaseClass

现在,我知道它正在尝试BaseClassSomeModule::SomeClass. 但这在几个小时前还在工作,然后在没有对这些文件进行任何更改后停止了。

所以,我可以直接加上 a::并与 一起使用class SomeClass < ::BaseClass,但不明白为什么感觉很糟糕,然后我想,我是否需要一直在我的所有代码中添加胡椒粉::

max*_*max 7

什么时候需要在 Ruby 常量前添加“::”前缀?

当你引用一个常量时,Ruby 会在当前模块嵌套中查找它。

module SomeModule
  puts Module.nesting.inspect # the current module nesting is [SomeModule] 
end
Run Code Online (Sandbox Code Playgroud)

模块嵌套主要通过使用module和设置class关键字打开类/模块来设置。

如果在那里没有找到它,它将在模块嵌套中继续向上,直到到达 main,如果到那时仍然没有找到常量,那么您将得到一个丢失常量的错误。

此错误可能会有些令人困惑,因为该消息包含开始查找常量的模块嵌套。

通过在常量前面加上前缀,::您可以显式地告诉 Ruby 从顶级命名空间解析该常量:

module Bar
  def self.hello
    puts "Hello from the top level Bar"
  end
end

module Foo
  module Bar


    def self.hello
      puts "Hello from Foo::Bar"
    end
  end

  def self.test
     Bar.hello # the current module nesting is Foo.
     ::Bar.hello
  end
end 

Foo.test
# Will output:
# Hello from Foo::Bar
# Hello from the top level Bar
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,这并不是严格必要的,但显式引用您自己的命名空间(依赖项)之外的常量是一个很好的做法。

那么为什么我的代码停止工作了?

如果没有实际的可复制示例,几乎不可能判断。它可能是“与程序员相关的问题”(您搞砸了并移动/删除/重命名了文件),也可能与使用中的自动加载器的问题有关。由于其猴子补丁的方式,经典的自动加载器更容易出现错误行为Object#constant_missing