这个怎么运作
Ruby 允许您在运行时重新定义类,因为class和def实际上是可执行代码。在您的示例中,代码执行以下操作:
- 定义一个 Example#one 方法,该方法将在调用实例方法时(重新)定义 Example#one 方法。
- 出于实际目的,在调用外部实例方法之前,不会执行内部def 。(头发分裂者可能会合理地争论这个定义,但这会涉及解析器/解释器的细节,这对于本讨论的目的并不重要。)
- 您定义了一个名为“ex”的 Example 实例。
- 您调用ex上的实例方法,它定义了一个具有相同名称的新方法。
- 当您再次调用实例方法时,将使用新方法而不是旧方法。
为什么有效
基本上,方法的最后一个定义替换了该命名空间中的任何早期定义,但这些方法实际上是新对象。您可以看到它的实际效果,如下所示:
def my_method
puts 'Old Method'
puts self.method(:my_method).object_id
def my_method
puts 'New Method'
puts self.method(:my_method).object_id
end
end
如果您在 irb 或 pry 会话中运行它,您可以看到在运行时重新定义的方法:
> my_method; puts; my_method
Old Method
8998420
New Method
8998360
从不同的对象 ID 可以看出,即使这些方法具有相同的名称并附加到同一个对象(通常是控制台上的main),它们实际上是不同的方法对象。但是,由于这些方法是用相同的名称定义的,因此在实例进行方法查找时只能找到最新的定义。