β

ruby的类变量

Ruby China社区 582 阅读

昨天(2013-5-4)本帖子,写的比较匆忙,论证不严谨,更主要水平有限,和@zgm 等等的讨论,深受启发,收益良多, 感谢

今天,重新写了一篇。http://ruby-china.org/topics/10715, 从类变量读写的角度,更易理解。

附上新贴的三条主要观点。
一、类变量的赋值
在本类的ancestors,反向查找。(即Ojbect中的类变量最优先----从Object类开始查找)
1.找到,直接赋值
2.找不到,在本类上创建类变量。
二、类变量的读取
在本类的ancestors,反向查找。
1.在父类中找到:返回父类中的类变量。(如果本类的有同名的类变量,同时被删除。)
2.在本类中找到:返回本类中的类变量。
3.找不到:报错。
三、singleton方法定义其他类中时,在外层类及父类中读取类变量(方法与上面两点,基本相同)。


原观点,比较难于理解,所以

加了下划线,没有删除。^_^

在动态编程时,ruby的类变量很容易出错.
方法中访问类变量
1. 方法定义的外层类的类变量。(外层,方法定义的静态位置!!!,注意singleton方法)
2. 外层类的父类的ancestors,反向查找。Ojbect中的类变量最优先!
3. inluded_modules中查找。

类定义中的类变量
1 .本类中的类变量。
2. 父类的ancestors,反向查找。Ojbect中的类变量最优先!
3. inluded_modules中查找。


一、方法的外层类是Object类.

class C; @@var = 1; end
def C.hi2
  @@var
end   
C.hi2            #err 因为此时方法的外层类是Ojbect,
self.class.class_variable_defined? :@@var  #=>false, Object类无@@var类变量,所以出错。

#这时可以使用class_eval方法切换 context
C.class_eval %{         
  def self.hi3;@@var; end
}
C.hi3   #=>1

#--多谢12楼 @zgm 指出, 下面D2例子有错---------------------------------
class C2;@@var2 = 200;end 
class D
  def self.hi1          #外层D类中没有定义@@var
    @@var
  end
end
D.hi1   #err
class C2
  def D.hi;@@var;end    # 方法的外层类的类变量@@var=200
end
D.hi   #=>200
#--- 方法的外层类中没有定义@@var=200,所以报错。这验证了关于外层的结论。----------------

二、父类Object中的@@var 覆盖 子类C3中的@@var

class C3; @@var3=100; end
class C33 < C3           
  def self.hi
     @@var3     #可以访问父类C3中的类变量
  end
end
C33.hi  #=>100

@@var3 = 200    #总父类Object中的@@var3,优先C3中的@@var
C33.hi  #=>>200
class C33
  @@var = 300   #修改的是Object类中的@@var
end
C33.hi     #=>300
@@var   #=>300

三、模块中的类变量(容易出错!!!)

module Mm; @@m=800; end
class CC
  include Mm
  def self.hi
    @@m
  end
end
CC.hi          #=>800
class CC2 < CC
  @@m = 900    #=>覆盖了Mm中的@@m
end
CC2.hi       #=>900
Mm.class_variable_get :@@m  #=>900,已经改变了Mm中的@@m

class CC3
  include Mm
  @@m    #=>这里@@m已经为900了!!!
end

四、class 关键字是类变量的切换门(静态位置)

class Q
  @@q= 1
  class Q2                      #class关键字,类变量门, 访问不到外层了。
    def self.hi
      @@q                      #访问不到外层的@@q
    end
  end
  @@q
end
Q::Q2.hi    #=>err  Q2中无类变量@@q

五、静态位置 > 继承 > include

# 静态位置优先与继承
class W; @@w = 1;end
class W11 < W; end
class W1x 
  @@w =2
  def W11.hi
      @@w
  end
end
W11.hi           #=>2 , ( 静态位置优先与继承)
W11.class_variable_get :@@w  #=>1

#----------------------------------------------
# 继承优先 include
class W2; @@w2=1; end
module M2  @@w2 =2; end
class W22 <W2 
  include M2
  p  @@w2       #=>1, 继承优先 include
end
M2.class_variable_get :@@w2  #=>2

#------------------------------------------------
# 静态位置有先与 include
module M3  @@w3 =2; end
class W3
  include M3
end
class W3x
  @@w3 = 1
  def W3.hi
      @@w3
  end
end
W3.hi     #=>3 , 静态位置有先与 include
W3.class_variable_get :@@w3  #=>2

总结
- 和常量类似,静态位置> 继承 > inlude
- class关键字是类变量空间切换门

作者:Ruby China社区
Ruby China社区最新发帖.
原文地址:ruby的类变量, 感谢原作者分享。