具有attr\u访问器的类上的Ruby实例\u eval

具有attr\u访问器的类上的Ruby实例\u eval,ruby,attr-accessor,class-eval,instance-eval,Ruby,Attr Accessor,Class Eval,Instance Eval,我理解实例评估和类评估之间的基本区别。不过,我在玩游戏时发现了一些奇怪的事情,涉及到attr\u访问器。下面是一个例子: A = Class.new A.class_eval{ attr_accessor :x } a = A.new a.x = "x" a.x => "x" # ... expected A.instance_eval{ attr_accessor :y } A.y = "y" => NoMethodError: undefined method `y='

我理解
实例评估
类评估
之间的基本区别。不过,我在玩游戏时发现了一些奇怪的事情,涉及到
attr\u访问器
。下面是一个例子:

A = Class.new
A.class_eval{ attr_accessor :x }

a = A.new
a.x = "x"
a.x
=> "x"  # ... expected

A.instance_eval{ attr_accessor :y }

A.y = "y"
=> NoMethodError: undefined method `y=' for A:Class

a.y = "y"
=> "y"      # WHATTT?
这是怎么回事:

  • 实例没有在访问器上评估我们的A类(对象)
  • 然后事实上它将它添加到了一个

  • 方法
    attr\u accessor
    是一种类方法,当在类的主体中调用时,访问器方法在该类的实例上定义

    当您执行
    A.class\u eval{…}
    时,您在
    A
    主体中调用它,因此它的实例
    A
    被分配了访问器

    当您执行
    A.instance\u eval{…}
    时,您在类的非主体中调用它,因此它的实例不被分配访问器


    如果您执行
    Class.Class_eval{attr\u accessor:z}
    ,那么您将使用类的主体调用它,因此,它的实例
    A
    将被分配访问器:
    A.z=…
    有关
    类评估
    实例评估
    之间的差异,请参阅


    正如您在B中所看到的,尽管实例求值通常创建单例方法,但显然
    attr\u accessor
    define\u method
    强制定义实例方法。

    首先,您的理解(或直觉)是正确的,在
    #instance_eval
    #class_eval
    中定义的方法不同

    A = Class.new
    
    A.instance_eval { def defined_in_instance_eval; :instance_eval; end }
    A.class_eval { def defined_in_class_eval; :class_eval; end }
    
    A.new.defined_in_class_eval # => :class_eval
    A.defined_in_instance_eval # => :instance_eval
    
    旁注:虽然
    self
    instance\u eval
    class\u eval
    中都是相同的,但是默认定义者不同,请参见

    真正的诀窍是
    模块#attr_访问器
    本身,看看它的定义:


    它不使用
    def
    ,不读取上下文、
    self
    或默认定义者。它只是“手动”将方法插入到模块中。这就是结果违反直觉的原因。

    伙计,这太糟糕了。很好的例子@Daniel_Vartanov的回答实际上解释了为什么
    attr_accessor
    不适用于self,但这是一个很好的方法,可以准确地说明每种类型的方法def'n会发生什么。非常感谢。
    A.singleton_class.class_eval { attr_accessor :y }
    A.y = 'y'
    A.y
    
    A = Class.new
    
    A.instance_eval { def defined_in_instance_eval; :instance_eval; end }
    A.class_eval { def defined_in_class_eval; :class_eval; end }
    
    A.new.defined_in_class_eval # => :class_eval
    A.defined_in_instance_eval # => :instance_eval
    
    A.singleton_class.class_eval { attr_accessor :y }
    A.y = 'y'
    A.y