我认为class << self
块中声明的方法与使用self.
前缀声明的方法之间没有区别,但有:
module A
VAR = 'some_constant'
end
class B
extend A
class << self
def m1
puts VAR
end
end
def self.m2
puts VAR
end
end
B.m1 # => OK
B.m2 # => uninitialized constant B::VAR
为什么A
中的m1
常量可用m2
而不是{{1}}?
答案 0 :(得分:22)
在Ruby中,常量查找与方法查找不同。对于方法查找,调用foo
始终与调用self.foo
相同(假设它不是私有的)。调用常量FOO
与self::FOO
或singleton_class::FOO
非常不同。
使用非限定常量(例如FOO
)将在当前打开的模块中进行查找。将使用module Mod
,class Klass
,class << obj
或module_eval
和变体打开一个模块。定义m1
时,这些是B
,然后是B.singleton_class
。定义m2
时,只会打开B
。
module Foo
X = 42
class Bar
def self.hello
X
end
end
end
在此代码中,Foo::Bar.hello
将返回42,即使X
不是Bar
的常量,也是其单例类或祖先。此外,如果您稍后向X
添加常量Bar
,则会返回该值。最后,以下定义不相同:
module Foo
X = 42
end
class Foo::Bar
def self.hello
X
end
end
Foo::Bar.hello # => uninitialized constant Foo::Bar::X
确实,在定义hello
时,只会打开课程Foo::Bar
,而在上一个示例中,Foo
和Foo::Bar
都会打开。
最后一个示例,显示显式范围与继承的区别:
class Base
X = 42
def self.foo
X
end
def self.bar
self::X
end
end
class Parent < Base
X = :other
end
Parent.foo # => 42
Parent.bar # => :other
在您的情况下,您可能希望include
您的模块,而不是extending
,不是吗?
否则,您可以使用singleton_class::VAR
,您的代码将按预期运行。
module A
VAR = 'some_constant'
end
class B
extend A
class << self
def m1
puts singleton_class::VAR # not necessary here, as singleton_class is opened
end
end
def self.m2
puts singleton_class::VAR # necessary here!
end
end
B.m1 # => OK
B.m2 # => OK