Ruby class_eval、class_exec、module_eval和module_exec之间有什么区别?

Ruby class_eval、class_exec、module_eval和module_exec之间有什么区别?,ruby,Ruby,我正在阅读模块文档,但似乎无法理解它们之间的差异以及应该在何处使用 eval与exec有何不同?首先回答您的最后一个问题,eval(在所有变体中)与exec完全不同exec$command将启动一个新进程来运行您指定的命令,然后在完成后退出 class_-eval和module_-eval具有重新定义类和模块的能力,即使是您自己没有编写的类和模块。例如,您可以使用类eval添加一个不存在的新方法 Fixnum.class_eval { def number; self; end } 7.numb

我正在阅读
模块
文档,但似乎无法理解它们之间的差异以及应该在何处使用


eval
exec
有何不同?

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

class_-eval
module_-eval
具有重新定义类和模块的能力,即使是您自己没有编写的类和模块。例如,您可以使用类eval添加一个不存在的新方法

Fixnum.class_eval { def number; self; end }
7.number # returns '7'
class_-eval
可用于添加实例方法,
instance_-eval
可用于添加类方法(是的,这一部分非常混乱)。类方法类似于
Thing.foo
——您实际上是在
Thing
类上调用
foo
方法。实例方法类似于上面的示例,使用
class\u eval
我已经向
Fixnum
的每个实例添加了
number
方法

好的,这就是
*\u 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中的许多工具,您可以使用其中任何一个来解决许多问题。很多时候,你甚至不需要这样做,除非你想对你使用的某个库定义的类进行猴子补丁(尽管这会打开一整罐蠕虫)。试着在irb中和他们一起玩,看看哪个更容易。我个人不会像使用
*\u exec
方法那样多地使用
*\u eval
方法,但这是我个人的偏好。

我将在你的问题中加入
实例{eval | exec}
来回答你的问题

{instance | module | class}{eval | exec}
的所有变体都会更改当前上下文,即
self
的值:

class Array
  p self                     # prints "Array"
  43.instance_eval{ p self } # prints "43"
end
现在来看看区别。
eval
版本接受字符串或块,而
exec
版本只接受块,但允许您向其传递参数:

def example(&block)
  42.instance_exec("Hello", &block)
end
example{|mess| p mess, self } # Prints "Hello" then "42"
eval
版本不允许传递参数。它提供了
self
作为第一个参数,尽管我想不出它的用途

最后,
模块{eval | exec}
与相应的
类{eval | exec}
相同,但它们与
实例{eval | exec}
略有不同,因为它们以不同的方式更改了当前打开的类(即受
定义
影响的内容):

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}
只能在
模块
上使用(因此

我想你把
exec
instance\u exec
搞混了吧?我在开头明确提到了exec
exec
eval
方法家族没有太多共同之处,就像
{instance | module | class}}U exec
一样。哦,我明白了。我认为OP的意思是
*\u eval
vs
*\u exec
,而不是
eval
vs
exec
,但我可能错了。注意:当您对lambda进行模块化时,它会将模块本身作为第一个参数传递给lambda。模块执行器没有,我没意识到。我想不出哪一种情况会有任何用处(改用
self
),但我已经编辑了完整的答案。谢谢你@Marc AndréLafortune,但是在上面的例子中,
mess
参数来自哪里?@BKSpurgeon第二次引用
&block
,其中
“你好”
作为
mess