我认为在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
Run Code Online (Sandbox Code Playgroud)
为什么常量A可用m1而不是m2?
Mar*_*une 24
在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
Run Code Online (Sandbox Code Playgroud)
在这段代码中,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
Run Code Online (Sandbox Code Playgroud)
实际上,在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
Run Code Online (Sandbox Code Playgroud)
在你的情况下,你可能想要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
Run Code Online (Sandbox Code Playgroud)