什么时候需要在Ruby常量前面加上“::“?(未初始化常量错误)

kkih6yb8  于 2022-11-22  发布在  Ruby
关注(0)|答案(1)|浏览(160)

错误类似于NameError: uninitialized constant Foo::Bar(当Bar不是Foo的后代时)。
我知道它与加载(自动加载?)常量有关,而且我 * 觉得 * lib/内部的任何内容都可以安全地不使用::作为前缀,因为它是自动加载的(或其他)。
我刚刚遇到的一个例子是这样的:

  • 应用程序/资产/类/基类.rb*
class BaseClass
end
  • 应用程序/资产/部分模块/部分类.rb*
module SomeModule
  class SomeClass < BaseClass
  end
end

我正在运行一个规范,并得到“加载[文件]时发生错误":NameError: uninitialized constant SomeModule::SomeClass::BaseClass .
现在,我知道它试图在SomeModule::SomeClass中查找BaseClass。但这在几个小时前还在工作,然后在没有对这些文件进行更改后停止。
所以,我可以只添加一个::,然后使用class SomeClass < ::BaseClass,但不明白为什么感觉不好,然后我想,我需要一直用::填充我所有的代码吗?

wn9m85ua

wn9m85ua1#

什么时候需要在Ruby常量前面加上“::“?
当你引用一个常量时,Ruby会在当前的模块嵌套中寻找它。

module SomeModule
  puts Module.nesting.inspect # the current module nesting is [SomeModule] 
end

模块嵌套主要通过使用moduleclass关键字打开类/模块来设置。
如果在那里没有找到它,它将在模块嵌套中继续向上,直到它到达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

在大多数情况下,这并不是绝对必要的,但是显式引用您自己的命名空间(依赖项)之外的常量是一个很好的做法。
那么为什么我的代码停止工作了呢?
如果没有一个实际的可复制的例子,这几乎是不可能的。这可能是“程序员相关的问题”(你搞砸了,移动/删除/重命名文件),也可能是使用中的自动加载器的问题。经典的自动加载器更容易出现错误行为,因为它的monkeypatch Object#constant_missing的方式。

相关问题