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

Kam*_*i81 43 ruby

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

有什么eval不同exec

Mar*_*une 84

通过instance_{eval|exec}在你的问题中加入,我会回答你的问题.

所有变化都会{instance|module|class}_{eval|exec}改变当前上下文,即self:

class Array
  p self                     # prints "Array"
  43.instance_eval{ p self } # prints "43"
end
Run Code Online (Sandbox Code Playgroud)

现在为了差异.该eval版本接受一个字符串或块,而exec版本只接受一个块,但允许您将参数传递给它:

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

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
Run Code Online (Sandbox Code Playgroud)

所以obj.instance_{eval|exec}打开单身类obj,同时mod.{class|module}_{eval|exec}打开mod自己.

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


tja*_*att 6

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

class_eval并且module_eval有能力重新定义类和模块 - 甚至是那些你自己没有写的东西.例如,您可以使用类eval添加不存在的新方法.

Fixnum.class_eval { def number; self; end }
7.number # returns '7'
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

Foo如果你知道正确的密钥,那么这个类只是一个秘密值的包装器.但是,你可以通过在类的上下文中执行一个块来欺骗类给你秘密,如下所示:

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

一般来说,使用ruby中的许多工具,您可以使用其中任何一个来解决许多问题.很多时候你甚至可能根本不需要,除非你想要修补你使用的某个类定义的类(尽管这会打开一大堆蠕虫).尝试用irb玩它们,看看哪个更容易找到.我个人并不像*_exec方法那样使用这些方法*_eval,但这是我个人的偏好.

  • 原来如此.我认为OP意味着`*_eval` vs`*_exec`,而不是'eval` vs`exec`,但我可能错了. (8认同)