Ruby 单例方法中的常量

Ruby constants in singleton methods

我有一个 Ruby C 扩展;我在 ext/foo/foo.c 中定义了 class FooC,在那个文件中我有

void Init_foo(void)
{
  VALUE cFoo = rb_const_get(rb_cObject, rb_intern("FooC"));
  :
  rb_define_const(cFoo, "BAR", 7);
  :

这包含在 lib/foo.rb 中扩展的“Ruby 部分”,如

class FooC ; end

require 'foo/foo'

class Foo < FooC
  class << self
    def puts_bar
      puts BAR
    end
    :
  end
  :
end

没想到报错

NameError: uninitialized constant #<Class:Foo>::BAR

我原以为 Ruby 不会在 Foo 命名空间中找到 BAR,但会搜索 FooC 它会找到它的地方。奇怪的是,如果我使用 Foo::BARself::BAR,错误就会消失,并且 Foo instance 方法中的类似用法不会给我任何错误全部.

有人知道为什么我需要在单例方法中对常量进行这种看似多余的限定吗?

[编辑]

根据下面有趣的回答,我确认在适当的 class 方法中 不需要 这个条件:

class Foo < FooC
  def self.puts_bar
    # no NameError here
    puts BAR
  end
  :
end

而不是本征的实例方法class.

您正在 Foo 的特征 class 中查找常量,而不是 Foo 本身。首先弄清楚没有任何 绑定是什么。

class FooC; end
class Foo < FooC
  BAR = 42
  puts "Foo: #{self}, DEF: #{const_defined?(:BAR)}"
  class << self
    def puts_bar
      puts "Foo.class: #{self} DEF: #{self.class.const_defined?(:BAR)}"
      puts self.class.const_get(:BAR)
    end
  end
  def puts_bar
    puts "Foo.class: #{self} DEF: #{self.class.const_defined?(:BAR)}"
    puts self.class.const_get(:BAR)
  end
end

看看它是如何工作的:

#  Foo: Foo, DEF: true

[2] pry(main)> Foo.puts_bar
#⇒ Foo.class: Foo DEF: false
#   NameError: uninitialized constant Class::BAR
#   from (pry):8:in `const_get'

[3] pry(main)> Foo.new.puts_bar
#⇒ Foo.class: #<Foo:0x0000556e174b91c0> DEF: true
#   42

常量在 实例函数 中可见,方法是查找 class 常量。 #<Class:Foo> 在您收到的错误消息中明确指出了这一点。