我无法理解为什么在以下示例中访问模块的类变量失败:
module M
@@xyz = 123
end
M.class_variables # [:@@xyz]
M.class_variable_get :@@xyz # 123 , so far so good
class C
extend M
end
C.singleton_class.class_variables # [:@@xyz]
C.singleton_class.class_variable_get :@@xyz # NameError:
# uninitialized class variable @@xyz in Class
有人可以解释为什么类变量@@xyz
在C
的单例类中突然变得无法/未定义吗?
更新 我使用不同的Ruby YARV版本重新测试了上面的代码,并在最新版本中将其作为回归。
更新2:
最新的Ruby生成中Module#class_variables
方法的定义发生了变化。
Ruby高达1.9.3,定义为
返回mod。
Ruby 2.0.0最新稳定版
class_variables(inherit=true)→数组
返回mod中类变量名称的数组。这个 包括任何包含的模块中的类变量的名称, 除非inherit参数设置为false。
因此,在最新的Ruby版本中,class_variables
默认返回包含模块的类变量。只是好奇这个功能是什么,或者它是否仍然涉及与include
而不是extend
“包含”的模块。
任何人都可以解释一下吗?
答案 0 :(得分:2)
不确定这些是否都是答案,但我确实找到了这些
C::M.class_variables #=> ["@@xyz"]
# (but gives "warning: toplevel constant M referenced by C::M")
和
class D
include M
end
D.class_variables #=> ["@@xyz"]
(这是来自Ruby 1.8.7,现在还没有更新的版本)。
include
使模块的实例方法成为类的实例方法。根据Pickaxe的说法,“这几乎就像模块成为使用它的类的超类”。
同时,extend
打算将模块的方法添加到对象;在类定义中调用时,它等同于self.extend
。看起来他们并不等同。
HTH。
答案 1 :(得分:1)
这不是答案,只是对这个问题的一些评论。
如果我们在课程M
中添加了模块C
,则C
会在M
中定义类变量:
module M
@@xyz = 123
end
class C
include M
end
C.class_variables #=> [:@@xyz]
C.class_variable_get(:@@xyz) # 123
在类定义中调用extend M
等同于在该类的特征类(或单例类)中调用include M
。
module M
@@xyz = 123
end
eigenclass = class C
class << self
include M
self
end
end
eigenclass.class_variables #=>[:@@xyz]
eigenclass.class_variable_get(:@@xyz) #=>NameError: uninitialized class variable @@xyz in Class
似乎不同之处在于Ruby以不同的方式对待普通类和特征类。
答案 2 :(得分:0)
简而言之,您观察到的差异是因为模块的工作方式与类不同。不久前我已经把这个问题交给了我的高层:Inheriting class methods from mixins
我得出结论,虽然Module在某些方面类似于Class,但在其他方面,Ruby仅将其视为普通对象。特别是,它被称为带有类(类方法,类变量......)的“类东西”,在其他对象(单例方法等)中被称为“单例东西”。模块的单例类在很多方面处理就像模块一样是普通的对象。
答案 3 :(得分:0)
关于特定的代码示例,它在我的Ruby 1.9.3p194上的工作方式不同:
module M
@@xyz = 123
end
M.class_variables # [:@@xyz]
M.class_variable_get :@@xyz # 123 , so far so good
class C
extend M
end
C.singleton_class.class_variables # [] - HERE BE THE DIFFERENCE
C.singleton_class.class_variable_get :@@xyz # NameError:
当然,那是我所期待的。 C.singleton_class是Class类的直接子类,我没看到你在Class或它的后代上设置任何类变量......但我相信你的代码就像你在你的机器上写的那样工作。