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