Ruby 类评估通过引用传递类变量
以下代码片段:Ruby 类评估通过引用传递类变量,ruby,class-eval,Ruby,Class Eval,以下代码片段: class A end @class = eval("A") @class.class_eval do @@attr = 100 def self.get_attr @@attr end def self.set_attr(_x) @@attr = _x end end class B end @cla
class A
end
@class = eval("A")
@class.class_eval do
@@attr = 100
def self.get_attr
@@attr
end
def self.set_attr(_x)
@@attr = _x
end
end
class B
end
@class = eval("B")
@class.class_eval do
@@attr = 100
def self.get_attr
@@attr
end
def self.set_attr(_x)
@@attr = _x
end
end
a = A.new
b = B.new
A.set_attr(103)
B.set_attr(222)
puts A.get_attr
puts B.get_attr
正在共享类变量
结果:
222
222这是因为你没有设置你认为你会做的变量
class A; end
@class = eval("A")
@class.class_eval do
class_variable_set :@@attr, 100
def self.get_attr
class_variable_get :@@attr
end
def self.set_attr(_x)
class_variable_set :@@attr, _x
end
end
class B
end
@class = eval("B")
@class.class_eval do
class_variable_set :@@attr, 100
def self.get_attr
class_variable_get :@@attr
end
def self.set_attr(_x)
class_variable_set :@@attr, _x
end
end
A.set_attr(103)
B.set_attr(222)
puts A.get_attr
puts B.get_attr
# >> 103
# >> 222
当我运行您的代码时,它给出了几个“从顶级访问类变量”的警告。显然,您正在设置和读取的是main
对象的类变量,而不是您的类变量。请参见以下代码:
class A
end
@class = eval("A")
@class.class_eval do
@@attr = 100
def self.get_attr
@@attr
end
def self.set_attr(_x)
p "hi"
@@attr = _x
end
end
class B
end
@class = eval("B")
@class.class_eval do
@@attr = 100
def self.get_attr
@@attr
end
def self.set_attr(_x)
p "hi"
@@attr = _x
end
end
a = A.new
b = B.new
A.set_attr(103)
B.set_attr(222)
p A.class_variable_defined?(:@@attr)
p B.class_variable_defined?(:@@attr)
p Object.class_variable_defined?(:@@attr)
p A.class_variable_get(:@@attr)
p B.class_variable_get(:@@attr)
p Object.class_variable_get(:@@attr)
p A.class_variables
p B.class_variables
Object.remove_class_variable(:@@attr)
p A.class_variables
p B.class_variables
输出:
说明:根据您的代码@@attr
属于对象类变量。根据Ruby
A和B都是Object
的子类。因此类变量@@attr
已被共享
说:
(a)这可用于向类添加方法。
(b)给定块时,常量/类变量查找不受影响。
这是ruby的特性,如果您在class_eval
中使用class变量
,它将在class对象中搜索class变量
为了使其可见,我编写了以下代码,这反过来将证明:常量/类变量查找不受影响。
检查下面的代码
class A
end
class B
end
ADD_ATTR = lambda do
@@attr = 100
def self.get_attr
puts "self : #{self} getting attr : #{@@attr}"
@@attr
end
def self.set_attr(_x)
puts "self : #{self} setting attr : #{@@attr} to _x : #{_x}"
@@attr = _x
end
end
A.class_eval &ADD_ATTR
B.class_eval &ADD_ATTR
a = A.new
b = B.new
A.set_attr(103)
B.set_attr(222)
puts A.get_attr
puts B.get_attr
ADD_BTTR = '
@@bttr = 100
def self.get_bttr
puts "self : #{self} getting bttr : #{@@bttr}"
@@bttr
end
def self.set_bttr(_x)
puts "self : #{self} setting bttr : #{@@bttr} to _x : #{_x}"
@@bttr = _x
end
'
A.class_eval ADD_BTTR
B.class_eval ADD_BTTR
A.set_bttr(103)
B.set_bttr(222)
puts A.get_bttr
puts B.get_bttr
ruby似乎在将对象方法加入类之前在对象方法的上下文中进行块求值,因此求值发生在代码附加到类之前,它需要将属性附加到对象方法,以证明我在代码中使用lambda运算符的观点
同时,如果我们使用字符串执行类eval,那么同样的代码也可以工作
这是我得到的输出:
self:A设置属性:100到_x:103
自:B设置属性:103到_x:222
self:A获取属性:222
222
self:B获取属性:222
222
self:A设置bttr:100至_x:103
自:B设置bttr:100至_x:222
self:A获得bttr:103
103
self:B获得bttr:222
222
那么,问题是什么?为什么类变量会被共享?我希望一些结果是103和222,而不是222和222,但class_eval应该将其添加到A/B类的范围中,对吗。@user2231847请查看我的更新答案和注释,如果有任何疑问,请发表评论。
@@avar = 1
class A < BasicObject
@@avar = "hello"
end
A.class_eval { puts @@avar }
D:/Rubyscript/My ruby learning days/Scripts/TEST.RB:91: warning: class variable
access from toplevel
D:/Rubyscript/My ruby learning days/Scripts/TEST.RB:95: warning: class variable
access from toplevel
1
class A
end
class B
end
ADD_ATTR = lambda do
@@attr = 100
def self.get_attr
puts "self : #{self} getting attr : #{@@attr}"
@@attr
end
def self.set_attr(_x)
puts "self : #{self} setting attr : #{@@attr} to _x : #{_x}"
@@attr = _x
end
end
A.class_eval &ADD_ATTR
B.class_eval &ADD_ATTR
a = A.new
b = B.new
A.set_attr(103)
B.set_attr(222)
puts A.get_attr
puts B.get_attr
ADD_BTTR = '
@@bttr = 100
def self.get_bttr
puts "self : #{self} getting bttr : #{@@bttr}"
@@bttr
end
def self.set_bttr(_x)
puts "self : #{self} setting bttr : #{@@bttr} to _x : #{_x}"
@@bttr = _x
end
'
A.class_eval ADD_BTTR
B.class_eval ADD_BTTR
A.set_bttr(103)
B.set_bttr(222)
puts A.get_bttr
puts B.get_bttr
self : A setting attr : 100 to _x : 103
self : B setting attr : 103 to _x : 222
self : A getting attr : 222
222
self : B getting attr : 222
222
self : A setting bttr : 100 to _x : 103
self : B setting bttr : 100 to _x : 222
self : A getting bttr : 103
103
self : B getting bttr : 222
222