扩展模块和扩展类变量访问?

时间:2013-04-19 07:23:59

标签: ruby

我无法理解为什么在以下示例中访问模​​块的类变量失败:

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

有人可以解释为什么类变量@@xyzC的单例类中突然变得无法/未定义吗?

更新 我使用不同的Ruby YARV版本重新测试了上面的代码,并在最新版本中将其作为回归。

更新2:

最新的Ruby生成中Module#class_variables方法的定义发生了变化。

  • Ruby高达1.9.3,定义为

    class_variables→数组

    返回mod。

  • 中类变量名称的数组
  • Ruby 2.0.0最新稳定版

    class_variables(inherit=true)→数组

    返回mod中类变量名称的数组。这个 包括任何包含的模块中的类变量的名称, 除非inherit参数设置为false。

因此,在最新的Ruby版本中,class_variables默认返回包含模块的类变量。只是好奇这个功能是什么,或者它是否仍然涉及与include而不是extend“包含”的模块。

任何人都可以解释一下吗?

4 个答案:

答案 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或它的后代上设置任何类变量......但我相信你的代码就像你在你的机器上写的那样工作。