Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 类评估通过引用传递类变量_Ruby_Class Eval - Fatal编程技术网

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