Ruby的def和instance_eval与class_eval

Jo *_*iss 29 ruby metaprogramming

我读的元编程部分编程Ruby 1.9的,我无法理解这是怎么回事内部之间class_eval/ class_exec对比instance_eval/ instance_exec.

首先,我的理解是defself(类对象)的方法表中添加一个方法:

class A
  puts self  # => A
  def foo; 42; end  # added to the method table of self, so becomes an instance method
end
A.new.foo  # => 42
Run Code Online (Sandbox Code Playgroud)

如果我们使用class_eval,我们会得到相同的行为:

A.class_eval do
  puts self  # => A
  def bar; 42; end  # same as above
end
A.new.bar  # => 42
Run Code Online (Sandbox Code Playgroud)

但不知何故,instance_eval情况有所不同:

A.instance_eval do
  puts self  # => A
  def baz; 42; end  # added to the method table of an anonymous
                    # singleton class of self, so becomes a class method
end
puts A.baz  # => 42

s = 'string'
s.instance_eval do ... end  # same behavior, so now def creates an instance method
Run Code Online (Sandbox Code Playgroud)

所以我理解class_eval和之间的功能差异instance_eval.

但是class_evalinstance_eval块中的上下文对我来说看起来完全一样 - 特别是self指向同一个对象,并且local_variables它们是相同的.那么块内(内部)正在发生什么样的def行为呢?

我能阅读一些文件吗?instance_evalclass_eval的RDoc 没有帮助.查看源代码,instance_eval似乎设置了一个单例类对象而class_eval没有 - 但是这个区别在C代码之外可见,在Ruby级别上?

kru*_*.ar 34

我认为你的困惑来自于def不依赖于当前的自我这一事实,你可能会认为它是一个拥有自己规则的"当前阶级".

按照你的例子:

class A
  # defs here go to A
  puts self  # => A
  class << self
     #defs here go to A's eigenclass
  end
end

A.class_eval do
  #defs here go to A
end

A.instance_eval do
  #defs here go to A's eigenclass     
end

s = "Hello World"

class << s
  #defs here go to s's eigenclass
end
Run Code Online (Sandbox Code Playgroud)

这一章的部分讨论了这个问题,并且很清楚这个行为

class_eval和instance_eval都在块的持续时间内设置self.但是,它们在为方法定义设置环境的方式上有所不同.class_eval设置就好像你在类定义的主体中一样,所以方法定义将定义实例方法相反,在类上调用instance_eval就好像你在self的单例类中工作一样.因此,您定义的任何方法都将成为类方法.

我认为唯一值得添加的是你可以在任何对象中调用instance_eval,而不仅仅是类,并且行为不会改变但会产生不同的后果.

一些相关的阅读:

Ruby:instance_eval和class_eval方法定义

这个最精彩的系列的第4章