class_eval,class_exec,module_eval和module_exec有什么区别?

我正在阅读Module文档,但似乎无法理解它们之间的差异,应该在哪里使用。

evalexec什么不同?

我将通过在您的问题中包含instance_{eval|exec}来回答您的问题。

{instance|module|class}_{eval|exec}所有变体都会改变当前的上下文 ,也就是self

 class Array p self # prints "Array" 43.instance_eval{ p self } # prints "43" end 

现在的差异。 eval版本接受一个string或一个块,而exec版本只接受一个块,但允许你传递参数给它:

 def example(&block) 42.instance_exec("Hello", &block) end example{|mess| p mess, self } # Prints "Hello" then "42" 

eval版本不允许传递参数。 它提供了self作为第一个参数,虽然我不能想到这个用法。

最后, module_{eval|exec}与相应的class_{eval|exec} ,但是它们与instance_{eval|exec}略有不同,因为它们改变了当前打开的类(即,什么会受到def ) 以不同的方式:

 String.instance_eval{ def foo; end } Integer.class_eval { def bar; end } String.method_defined?(:foo) # => false String.singleton_methods.include?(:foo) # => true Integer.method_defined?(:bar) # => true 

所以obj.instance_{eval|exec}打开obj的单例类,而mod.{class|module}_{eval|exec}打开mod本身。

当然, instance_{eval|exec}可以在任何Ruby对象(包括模块)上使用,而{class|module}_*仅在Module (和Classes

要首先回答你的最后一个问题,eval(所有变体)与exec 完全不同。 exec $command将启动一个新的进程来运行你指定的命令,然后在完成时退出。

class_evalmodule_eval有能力重新定义类和模块 – 即使是你自己没有写的。 例如,您可以使用class eval来添加一个不存在的新方法。

 Fixnum.class_eval { def number; self; end } 7.number # returns '7' 

class_eval可以用来添加实例方法,而instance_eval可以用来添加类方法(是的,这部分是非常混乱的)。 类方法就像Thing.foo – 你真的在Thing类中调用foo方法。 一个实例方法就像上面的例子,使用class_eval我已经给每个Fixnum实例添加了一个number方法。

好的,这是*_eval类的方法。 exec方法是相似的,但是它们允许你查看一个类的内部并执行一个代码块,就像它被定义为该类的一个方法一样。 也许你有一个看起来像这样的类:

 class Foo @@secret = 'secret key' @@protected = 'some secret value' def protected(key) if key == @@secret return @@protected end end end 

如果你知道正确的密钥, Foo类只是一些秘密值的包装。 然而,你可以通过在类的上下文中执行一个块来欺骗类给你的秘密,就像这样:

 Foo.class_exec { @@secret = 'i'm a hacker' } Foo.protected('i'm a hacker') #returns the value of @@protected because we overwrote @@secret 

一般来说,在Ruby中有很多工具,你可以使用这些工具来解决很多问题。 很多时候,你可能甚至不需要,除非你想猴子补丁一些你使用的库已经定义的类(虽然这打开了一整jar蠕虫)。 尝试在irb中与他们玩耍,看看你更容易find。 我个人并不像*_exec方法那样使用*_eval方法,但这是我个人的偏好。