首页 > 解决方案 > 动态获取定义的常量

问题描述

根据 Rubyconst_get的文档,此方法返回常量的值。

因此要重现以下行为:

module A
  FOO = 42

  module B
    def self.call
      FOO
    end
  end
end

A::B.call # => 42

我写了这段代码:

A = Module.new
A.const_set(:FOO, 42)
A.const_set(:B, Module.new do
  def self.call
    const_get(:FOO)
  end
end)

但是当我调用该方法时,我遇到了一个NameError异常:

A::B.call # => exception
# NameError (uninitialized constant A::B::FOO)
# Did you mean?  A::FOO

它看起来FOOconst_get(:FOO)不完全相同。

是否有另一种方法可以FOO在父模块中递归查找常量?

编辑:

我直接做也有这个麻烦const_get

module A
  FOO = 42

  module B
    def self.a_method
      const_get(:FOO)
    end
  end
end

A::B.a_method # => exception
# NameError (uninitialized constant A::B::FOO)
# Did you mean?  A::FOO

标签: rubymetaprogramming

解决方案


我们可以使用Module::nesting方法来更好地理解这里发生了什么。

module A
  FOO = 42
  module B
    puts "Module.nesting = #{Module.nesting}"
    def self.call
      FOO
    end
  end
end

显示

Module.nesting = [A::B, A]

这告诉我们,在执行 时A::B.call,在搜索 的值时FOO,Ruby 首先在 moduleA::B中查找,没有找到,然后在A找到它的 module 中搜索。

您的第三个代码片段还创建了一个嵌套模块A::B

module A
  FOO = 42
  module B
    puts "Module.nesting = #{Module.nesting}"
    def self.a_method
      const_get(:FOO)
    end
  end
end

显示

Module.nesting = [A::B, A]

A::B.a_method执行A::B.const_get(:FOO)Module#const_get的文档指出,“在 mod 中检查具有给定名称的常量。” 因此,如果它未能在作为其接收者的模块中找到常量,它会放弃而不检查给定模块嵌套的任何模块。

您的第二个代码片段与第三个代码片段相似,因为它无法找到 的值,FOO因为const_get.


推荐阅读