10

我不明白为什么在以下示例中访问模​​块的类变量会失败:

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:

Module#class_variables在最新一代的 Ruby 中,方法的定义发生了变化。

  • Ruby 到 1.9.3 的定义是

    类变量→ 数组

    返回 mod 中类变量名称的数组。

  • Ruby 2.0.0 最新稳定版

    class_variables(inherit=true) → 数组

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

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

谁能解释一下?

4

4 回答 4

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。

于 2013-04-19T08:02:39.730 回答
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对普通类和特征类的处理方式不同。

于 2013-04-19T08:46:05.030 回答
0

简而言之,您观察到的差异是因为模块的工作方式与类不同。不久前我向我的上级提出了这个问题:Inheriting class methods from mixins

我得出的结论是,虽然 Module 在某些方面类似于 Class,但在其他方面,Ruby 将其简单地视为普通对象。特别是,在其他对象(单例方法等)中被称为“类东西”的类(类方法、类变量......)只是被称为“单例东西”。模块的单例类在很多方面都有就像模块一样被视为普通对象。

于 2013-04-19T08:31:05.183 回答
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 的直接子类,我在任何地方都没有看到你在 Class 或其后代上设置任何类变量......但我相信你的代码按照你在机器上编写的方式工作。

于 2013-04-19T08:48:45.360 回答