instance_eval vs模块中的class_eval

Nic*_*ilt 5 ruby

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

    def lab
      super 
      puts 'c'
    end
end

Foo.new.lab #=> m c
Run Code Online (Sandbox Code Playgroud)

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

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

    def lab
      super 
      puts 'c'
    end
end
Run Code Online (Sandbox Code Playgroud)

请注意,我将class_eval更改为instance_eval

Foo.new.lab rescue nil#=> no super class method lab
Foo.lab #=> undefined method lab for Foo class
Run Code Online (Sandbox Code Playgroud)

所以似乎包含模块既没有定义实例方法也没有定义类方法.

有什么解释在这里发生了什么?

此代码在mac上的ruby 1.8.7上进行了测试.

mik*_*kej 10

首先,想一想是什么include.它使模块的实例方法被包含在包含类的实例方法中.即,除了您的工作示例使用匿名模块这相当于:

module M1
  def lab
    puts 'm'
  end
end

class Foo
    include M1

    def lab
      super 
      puts 'c'
    end
end
Run Code Online (Sandbox Code Playgroud)

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

module MyModule
  def lab
    puts 'm'
  end
end
Run Code Online (Sandbox Code Playgroud)

希望这能解释有效的案例.

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

module MyMod2
  def MyMod2.lab
    puts 'm'
  end
end
Run Code Online (Sandbox Code Playgroud)

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


请注意:这个答案从我写给前一个问题的答案中借用了一些解释,这个问题询问了与Ruby编程语言书中的一个例子有关的instance_eval与class_eval.您可能会发现答案也很有用.