我正在阅读Module
文档,但似乎无法理解它们之间的区别,哪些应该在哪里使用。
eval
与exec
有什么不同?
答案 0 :(得分:83)
通过在问题中加入instance_{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
作为第一个参数,尽管我无法想到它的用途。
最后,module_{eval|exec}
与相应的class_{eval|exec}
相同,但它们与instance_{eval|exec}
略有不同,因为它们会更改当前打开的类(即受{影响的内容) {1}})以不同的方式:
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
可用于任何Ruby对象(包括模块),而instance_{eval|exec}
仅适用于{class|module}_*
(因此Module
)
答案 1 :(得分:6)
首先回答你的上一个问题,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
- 您实际上是在foo
类上调用Thing
方法。实例方法与上面的示例类似,使用class_eval
我已为number
的每个实例添加了Fixnum
方法。
好的,那就是*_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玩它们,看看哪个更容易找到。我个人不像*_exec
方法那样使用*_eval
方法,但这是我个人的偏好。