【问题标题】:instance_eval vs class_eval in module模块中的 instance_eval 与 class_eval
【发布时间】:2011-04-01 05:07:21
【问题描述】:
class Foo
    include Module.new { class_eval "def lab; puts 'm' end" }

    def lab
      super 
      puts 'c'
    end
end

Foo.new.lab #=> m c

================================================ ==========================

class Foo
    include Module.new { instance_eval "def lab; puts 'm' end" }

    def lab
      super 
      puts 'c'
    end
end

注意这里我把 class_eval 改成了 instance_eval

Foo.new.lab rescue nil#=> no super class method lab
Foo.lab #=> undefined method lab for Foo class

所以看起来包含模块既没有定义实例方法也没有定义类方法。

任何解释这里发生了什么?

此代码已在 mac 上的 ruby​​ 1.8.7 上测试。

【问题讨论】:

    标签: ruby


    【解决方案1】:

    首先,想想include 做了什么。它使模块的 instance 方法包含在包含类的 instance 方法中。即除了您的工作示例使用匿名模块这一事实之外,它等同于:

    module M1
      def lab
        puts 'm'
      end
    end
    
    class Foo
        include M1
    
        def lab
          super 
          puts 'c'
        end
    end
    

    接下来,想想class_eval 做了什么。它在类或模块的上下文中评估给定的代码。也就是说,就像您重新打开模块并输入传递给class_eval 的代码一样。所以MyModule = Module.new { class_eval "def lab; puts 'm' end" }相当于

    module MyModule
      def lab
        puts 'm'
      end
    end
    

    希望这能解释有效的情况。

    当您使用instance_eval 时,您正在评估接收对象(在本例中为模块实例)的上下文中的代码,因此MyMod2 = Module.new { instance_eval "def lab; puts 'm' end" } 等效于

    module MyMod2
      def MyMod2.lab
        puts 'm'
      end
    end
    

    即它创建了一个 module 方法,您可以通过 MyMod2.lab 调用该方法,并且 include 不会将此类方法添加为实例方法。


    请注意:这个答案借用了我写给previous question asking about instance_eval vs. class_eval 的答案的一些解释,该答案与 The Ruby Programming Language 书中的一个示例有关。您可能会发现该答案也很有帮助。

    【讨论】:

    • 很好的解释。把事情拆开,一步一步地看待它会有所帮助。
    【解决方案2】:

    包含一个模块只需要实例方法 - 您正在寻找扩展。幸运的是,想要两全其美,您可以这样做:

    module Something
      def self.included(base)
        base.extend ClassMethods
      end
    
      module ClassMethods
        def blah
          puts "lol"
        end
      end
    end
    
    class Test
      include Something
    end 
    

    irb:

    >> Test.blah
    lol
    => nil
    

    【讨论】:

      猜你喜欢
      • 2012-05-05
      • 1970-01-01
      • 2011-05-23
      • 2017-05-06
      • 2017-04-22
      • 1970-01-01
      • 2011-03-11
      • 2013-05-13
      • 2010-10-28
      相关资源
      最近更新 更多