动态获取已定义的常量

3
根据Ruby的const_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

3
请查看关于常量查找的文章。顺便说一句,使用与核心方法相同的方法名称(例如call)可能会令人困惑,甚至有问题。 - Cary Swoveland
5
module A内部定义module B与直接定义module A::B实际上是不同的。嵌套的方式意味着在另一种方式下不存在的搜索范围。 - tadman
我同意@tadman的评论,并添加了另一个示例以确保代码与工作的“FOO”一致。唯一的区别是,我用const_get(:FOO)替换了FOO。但它不再起作用了。所以我认为问题来自于const_get方法。 - Zag zag..
1个回答

0

我们可以使用方法 模块::嵌套 来更好地理解这里正在发生的事情。

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 首先查找模块 A::B,未找到,然后搜索模块 A,在那里找到了它。
您的第三个代码片段还创建了一个嵌套模块 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 中检查具有给定名称的常量。” 因此,如果它在其接收器模块中找不到常量,则会放弃而不检查给定模块所嵌套的任何模块。

你的第二个代码片段与第三个类似,因为 const_get 的行为而无法找到 FOO 的值。


我通过您的解释更好地理解了。但是,如何(在纯元编程中)创建一个带有常量和子模块的模块,并通过类方法获取常量呢?这不可能吗? - Zag zag..
我不确定我理解了。如果 module A; FOO = 1; module B; def self.b; "FOO=#{FOO}"; end; end; end,那么 A::B.b #=> "FOO=1"。这是你的意思吗?我写作时,我的狗在拉我的裤腿,告诉我该去散步了。稍后再联系。 - Cary Swoveland

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接