define_method如何使用在其外部初始化的变量

时间:2013-11-02 14:24:14

标签: ruby-on-rails ruby metaprogramming

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 ='哈哈',方法将以某种方式打印'哈哈'。有人可以解释一下吗?

另外,我没有看到使用class_eval或instance_eval之间的区别,看起来它做同样的事情。

最后但并非最不重要的是,我可以使用define_method在这里创建类方法吗?所以我可以把它称为Temp1.something而不是Temp1.new.something?

1 个答案:

答案 0 :(得分:4)

因为块(do ... end)是闭包并且可以访问它们 周边范围。

您使用了class_eval的块,因此它可以访问其周围环境,这是方法add的范围。现在,您使用define_method的另一个块,该块也可以通过add的块访问方法范围class_evalmatch局部变量已被在方法add的范围内创建。因此块可以访问变量。

  

最后但并非最不重要的是,我可以使用define_method创建类方法吗?

不,你不能。define_method 在接收器中定义实例方法self.classTemp1。现在在Temp1.class_eval do..end下,您正在使用方法Temp1定义类define_method的实例方法。define_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

希望这有帮助!