2013-11-02 52 views
1
class Temp1 
    def add(s) 
    match = 'test' 
    self.class.class_eval do 
     define_method(s) do 
     puts match 
     end 
    end 
    #match ='haha' 
    end 
end 

正如我認爲它,「匹配」是一個局部變量,所以我不知道如何可以從另一種方法看出來,再加上如果取消註釋#match =」哈哈',方法會打印'哈哈'莫名其妙。有人可以解釋嗎?如何define_method使用變量初始化之外它

此外,我沒有看到使用class_eval或instance_eval之間的區別,似乎它做同樣的事情。

最後但並非最不重要的是,我可以使用define_method在這裏創建類方法嗎?所以我可以稱它爲Temp1.something而不是Temp1.new.something?

回答

3

因爲塊(do ... end)是關閉並且可以訪問它們的周圍範圍 。

您在class_eval中使用了塊,因此它可以訪問其周圍環境,這是方法add的範圍。現在使用define_method的另一個塊,它也可以通過class_eval的塊訪問方法add的範圍。 match局部變量已在方法add的範圍內創建。所以塊有權訪問變量。

而且,最後但並非最不重要的是,我可以使用define_method在這裏創建類方法嗎?

不,你不能。 define_method定義接收器中的實例方法。 self.classTemp1。現在在Temp1.class_eval do..end之下,您正在定義類Temp1的實例方法,方法define_methoddefine_method是所有類的私人類方法,其中祖先鏈Object類存在。

class C;end 
C.private_methods.grep(/define_/) 
# => [:define_method] 

而且,我在這裏看不到區別使用class_evalinstance_eval之間,好像它做同樣的事情。

好吧!讓我爲你解釋。您看不到這裏的區別,因爲Teamp1Class,也是Class的一個實例。在呼叫class_evalinstance_eval中,self被設置爲Teamp1,通過它們各自的定義記錄。

class C 
    def self.bar;11;end 
    def baz;12;end 
end 

C.is_a? Class # => true 
C.instance_of? Class # => true 

C.class_eval{ bar } # => 11 
C.instance_eval{ bar } # => 11 

希望這有助於!