繁体   English   中英

Ruby的def和instance_eval与class_eval

[英]Ruby's def and instance_eval vs. class_eval

我正在阅读Programming Ruby 1.9的Metaprogramming部分,我无法理解class_eval / class_execinstance_eval / instance_exec之间的内部 instance_exec

首先,我的理解是defself (类对象)的方法表添加了一个方法:

class A
  puts self  # => A
  def foo; 42; end  # added to the method table of self, so becomes an instance method
end
A.new.foo  # => 42

如果我们使用class_eval ,我们会得到相同的行为:

A.class_eval do
  puts self  # => A
  def bar; 42; end  # same as above
end
A.new.bar  # => 42

但不知何故,在instance_eval案例中,情况有所不同:

A.instance_eval do
  puts self  # => A
  def baz; 42; end  # added to the method table of an anonymous
                    # singleton class of self, so becomes a class method
end
puts A.baz  # => 42

s = 'string'
s.instance_eval do ... end  # same behavior, so now def creates an instance method

所以我理解class_evalinstance_eval之间的功能差异。

但是class_evalinstance_eval块中的上下文对我来说看起来完全相同 - 特别是, self指向同一个对象,而local_variables是相同的。 所以,这是怎么回事块(内部)这是制作内def作用有什么不同?

我能阅读一些文件吗? instance_evalclass_eval的RDoc没有帮助。 查看源代码, instance_eval似乎设置了一个单例类对象而class_eval没有 - 但是这个区别在C代码之外可见,在Ruby级别上?

我认为你的困惑来自于def不依赖于当前的自我这一事实,你可能会认为它是一个拥有自己规则的“当前阶级”。

按照你的例子:

class A
  # defs here go to A
  puts self  # => A
  class << self
     #defs here go to A's eigenclass
  end
end

A.class_eval do
  #defs here go to A
end

A.instance_eval do
  #defs here go to A's eigenclass     
end

s = "Hello World"

class << s
  #defs here go to s's eigenclass
end

这一章的部分讨论了这个问题,并且很清楚这个行为

class_eval和instance_eval都在块的持续时间内设置self。 但是,它们在为方法定义设置环境的方式上有所不同。 class_eval设置就好像你在类定义的主体中一样,所以方法定义将定义实例方法相反,在类上调用instance_eval就好像你在self的单例类中工作一样。 因此,您定义的任何方法都将成为类方法。

我认为唯一值得添加的是你可以在任何对象中调用instance_eval,而不仅仅是类,并且行为不会改变但会产生不同的后果。

一些相关的阅读:

Ruby:instance_eval和class_eval方法定义

这个最精彩的系列的第4章

只是添加到@ krusty.ar的答案: defdefine_method将方法添加到当前方法定义上下文 (我相信它的名称,我不确定),而不是当前的self

只是在模块,类或单例类体内部,这两者恰好相同。

但是,例如,在脚本体(也称为顶级)中, selfmain对象,但当前方法定义上下文是Object

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM