昨天(2013-5-4) 本帖子,写的比较匆忙,论证不严谨,更主要水平有限,和@zgm 等等的讨论,深受启发,收益良多,感谢
附上新贴的三条主要观点。 一、类变量的赋值 在本类的 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
总结
class 关键字是类变量空间切换门
Object 中的类变量,相当于全局变量。(如果在 Kernel 中猴子补丁可访问?)
父类中的类变量与子类中的同名类变量是 同一个类变量。
singleton 方法定义中访问类中的类变量,可以用 class_eval 方法切换