首页 > 代码库 > 谈谈Ruby中的类变量

谈谈Ruby中的类变量

Ruby中的类变量,很多文章都是不太建议使用的,主要原因在于他的一些特性容易导致犯一些错误,尤其在广泛使用元编程的时候。

初步接触类变量可能觉得他跟C++的类静态成员和Java中的静态变量没什么区别,但在实际使用中一不留神就会掉到类变量的陷阱中去

陷阱1,类变量跟类实例变量不同,类实例变量关联的是self,但类变量关联的是当前类作用域

class Cendclass Dendclass C  @@var = "C"  def D.getvar    @@var  endendclass D  @@var = "D"  def C.getvar    @@var  endendC.getvar#=> "D"D.getvar#=> "C"

在这个例子里面我在类C里面定义D的方法,在D里面定义C的方法,结果C的方法返回了D的类变量,而D的方法返回了C的类变量,这就是由于类变量跟当前环境的self无关,只跟所在环境的类作用域有关,如果不包含在class关键字中,则视为在Object中。

是不是感觉有点怪怪的啊,不过更怪的还在后面。

陷阱2,超类如果增加一个子类已有的同名类变量,会将子类的类变量污染

我们知道类的继承带有引用性质,在一个引用树上,子类可以重写超类的方法和变量而不对超类产生影响,但对于类变量这个事情不成立

类变量在整个继承树中只有一个实体,首先超类中如果有类变量,子类完全继承,而子类中的类变量原则上是不影响超类的,但一旦超类中加入了相同的类变量就会自动把子类的类变量重写!!

class C  @@var1 = "C_var1"  def getvar    @@var1  end  def setvar    @@var2 = "C_var2"  endendclass D < C  @@var2 = "D_var2"  def getvar    @@var2  endendc = C.newd = D.newp c.getvar#"C_var1"p d.getvar#"D_var2"c.setvarp c.getvar#"C_var1"p d.getvar#"C_var2"

可以看到,子类和超类有各自的同名实例函数,但是却共享一个相同的类变量名。

陷阱3,跟陷阱2类似,Object中如果定义一个类变量,会将所有类中的同名类变量污染

同样的,如果两个不同的子类中有两个相同的类变量,这本来是不干扰的,但是一旦他们共同的超类定义了该类变量,这三个类变量就会强制统一!!

而我们知道类共同的超类是Object,那么一旦你在Object中定义了一个类变量,就会导致所有的类的同名类变量都受到污染!!

class C  @@var = "C_var"  def getvar    @@var  endendclass D  @@var = "D_var"  def getvar    @@var  endendc = C.newd = D.newp c.getvar# "C_var"p d.getvar# "D_var"class Object  @@var = "Object_var"end# @@var = "main_var"# 使用这句有同样的效果,不过会得到一个警告p c.getvar# "Object_var"p d.getvar# "Object_var"

类变量在一个继承树中只能有一个,不允许重写,但在不同的继承树中却允许重名,这个奇葩的东西还是少碰点的好

因此慎用类变量,尤其是不要用猴子补丁来定义类变量,我甚至觉得这个奇怪的东西应该从Ruby中拿掉。

 

谈谈Ruby中的类变量