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::BAR
或 self::BAR
,错误就会消失,并且 Foo
instance 方法中的类似用法不会给我任何错误全部.
有人知道为什么我需要在单例方法中对常量进行这种看似多余的限定吗?
[编辑]
根据下面有趣的回答,我确认在适当的 class 方法中 不需要 这个条件:
class Foo < FooC
def self.puts_bar
# no NameError here
puts BAR
end
:
end
而不是本征的实例方法class.
您正在 Foo
的特征 class 中查找常量,而不是 Foo
本身。首先弄清楚没有任何 c 绑定是什么。
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>
在您收到的错误消息中明确指出了这一点。
我有一个 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::BAR
或 self::BAR
,错误就会消失,并且 Foo
instance 方法中的类似用法不会给我任何错误全部.
有人知道为什么我需要在单例方法中对常量进行这种看似多余的限定吗?
[编辑]
根据下面有趣的回答,我确认在适当的 class 方法中 不需要 这个条件:
class Foo < FooC
def self.puts_bar
# no NameError here
puts BAR
end
:
end
而不是本征的实例方法class.
您正在 Foo
的特征 class 中查找常量,而不是 Foo
本身。首先弄清楚没有任何 c 绑定是什么。
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>
在您收到的错误消息中明确指出了这一点。