为什么instance_exec和class_exec有这种不同的行为?

时间:2012-07-02 06:57:06

标签: ruby metaprogramming

我在instance_exec

的文档中找到了以下代码摘录
  class KlassWithSecret
    def initialize
      @secret = 99
    end
  end
  k = KlassWithSecret.new
  k.instance_exec(5) {|x| @secret+x }   #=> 104

我对instance_exec的作用的理解如下图所示,它在其单例类中添加@secret + 5

  +-----------------------+
  |   singleton class do  |
  |     def method1       |
  |     ...               |
  |     end               |
  |     ...               |
  |     @secret + 5       |
  |   end                 |
  |                       |
  |                       |
  +-----------+-----------+
              |
    +---------+-------+
    |  instance k     |
    |   @secret       |
    |                 |
    +-----------------+

所以我想出了使用class_exec得到相同结果的代码

k.singleton_class.class_exec(5) {|x| @secret + x}

它给我一个@secret是零错误,我想知道为什么它和我的理解有什么不对

更新

我注意到k.instance_exec {binding}和k.singleton_class.class_exec {binding}具有不同的绑定对象,因此它们必须是不同的。我仍然想知道它们是如何在引擎盖下工作的

1 个答案:

答案 0 :(得分:1)

instance_exec是用C语言编写的,c-api允许你指定执行方法时self的值。

在它变成ruby之前,人们通过在单例类上定义一个方法并调用它来实现它,而不仅仅是在singleton类的上下文中执行东西(你可以在activesupport 2.x或rspec_core中看到它) instance_eval_with_args

对象的单例类本身就是一个对象,因此有自己的一组实例变量,它们不与相应的对象共享