簡體   English   中英

帶有attr_accessor的類上的Ruby instance_eval

[英]Ruby instance_eval on a class with attr_accessor

我理解instance_evalclass_eval之間的基本區別。 我在玩游戲時發現的東西是涉及到attr_accessor奇怪之attr_accessor 這是一個例子:

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?

怎么樣:

  1. instance_eval沒有在我們的A類(對象)的訪問器上
  2. 然后它實際上把它添加到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

一個側面說明:雖然self是在兩個相同的instance_evalclass_eval默認definee不同的是,看到http://yugui.jp/articles/846

真正的訣竅是Module#attr_accessor本身,看看它的定義: httpModule#attr_accessor

它不使用def ,它不讀取上下文, self或默認的definee。 它只是“手動”將方法插入到模塊中。 這就是結果違反直覺的原因。

有關class_evalinstance_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)

輸出(紅寶石1.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_accessordefine_method強制實例方法的定義。

A.singleton_class.class_eval { attr_accessor :y }
A.y = 'y'
A.y

方法attr_accessor是一個類方法,當在主體中調用時,然后在該類的實例上定義訪問器方法。

當你執行A.class_eval{...} ,你在 A主體內調用它,因此它的實例 (如a被分配了訪問器。

當您執行A.instance_eval{...} ,您在A 非主體內調用它,因此其實例未分配訪問者。

如果你做Class.class_eval{attr_accessor :z} ,那么你用 Class主體調用它,所以它的實例A將被賦予訪問器: Az = ...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM