带有attr_accessor的类上的Ruby instance_eval
我理解instance_eval
和class_eval
之间的基本区别。 我在玩游戏时发现的是涉及attr_accessor
奇怪之attr_accessor
。 这是一个例子:
A = Class.new A.class_eval{ attr_accessor :x } a = A.new ax = "x" ax => "x" # ... expected A.instance_eval{ attr_accessor :y } Ay = "y" => NoMethodError: undefined method `y=' for A:Class ay = "y" => "y" # WHATTT?
怎么样:
- instance_eval没有在我们的A类(对象)的访问器上
- 然后它实际上把它添加到A的实例?
首先,你的理解(或直觉)是正确的, #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
旁注:虽然class_eval
和class_eval
self
相同,但默认的definee是不同的,请参阅http://yugui.jp/articles/846
真正的诀窍是Module#attr_accessor
本身,看看它的定义: http : Module#attr_accessor
它不使用def
,它不读取上下文, self
或默认的definee。 它只是“手动”将方法插入到模块中。 这就是结果违反直觉的原因。
有关class_eval
和instance_eval
之间的区别,请参阅动态创建类方法
class A; end A.class_eval do attr_accessor :x def barx; end define_method :foox do; end end print 'A.instance_methods : '; p A.instance_methods(false).sort print 'A.singleton_methods : '; p A.singleton_methods class B; end B.instance_eval do attr_accessor :y def bary; end define_method :fooy do; end end print 'B.instance_methods : '; p B.instance_methods(false).sort print 'B.singleton_methods : '; p B.singleton_methods class C; end singleton_class = class << C; self end singleton_class.instance_eval do attr_accessor :z def barz; puts 'where is barz ?' end define_method :fooz do; end end print 'C.instance_methods : '; p C.instance_methods(false).sort print 'C.singleton_methods : '; p C.singleton_methods print 'singleton_class.barz : '; singleton_class.barz print 'singleton_class.methods : '; p singleton_class.methods(false)
输出(ruby1.8.6):
A.instance_methods : ["barx", "foox", "x", "x="] A.singleton_methods : [] B.instance_methods : ["fooy", "y", "y="] B.singleton_methods : ["bary"] C.instance_methods : [] C.singleton_methods : ["z", "z=", "fooz"] singleton_class.barz : where is barz ? singleton_class.methods : ["barz"]
正如您在B中看到的那样,尽管instance_eval通常会创建单例方法,但显然attr_accessor
和define_method
强制实例方法的定义。
A.singleton_class.class_eval { attr_accessor :y } Ay = 'y' Ay
方法attr_accessor
是一个类方法,当在类的主体中调用时,然后在该类的实例上定义访问器方法。
当你执行A.class_eval{...}
,你在类 A
的主体内调用它,因此它的实例 (如a
被分配了访问器。
当你执行A.instance_eval{...}
,你在A
类的非体内调用它,因此它的实例没有分配访问器。
如果你做Class.class_eval{attr_accessor :z}
,那么你用类 Class
的主体调用它,所以它的实例如A
将被赋予访问器: Az = ...