以下代码如何运作,更重要的是,为什么它会以这种方式运作?
class Example
def one
def one
@value = 99
end
puts "Expensive Call"
@value = 99 # assume its expensive call
end
end
ex = Example.new
puts ex.one # => "Expensive Call"; 99
puts ex.one # => 99
这里,在第一次调用方法one
时,Ruby执行外部one
方法,但在连续调用时,它只执行内部one
方法,绕过外部{{1}方法完全。
我想知道它是如何发生的,为什么会这样。
答案 0 :(得分:7)
第一次执行时,它会在类中重新定义,然后完成。第二次,方法one
本身已被覆盖为@value = 99
,因此不会打印任何内容。
答案 1 :(得分:6)
Ruby允许您在运行时重新定义类,因为 class 和 def 实际上是可执行代码。在您的示例中,代码执行以下操作:
基本上,该命名空间中方法replaces any earlier definitions的最后一个定义,但这些方法实际上是新对象。您可以按如下方式查看此操作:
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 ),它们实际上也是不同的方法对象。但是,由于方法是使用相同的名称定义的,因此当实例执行method lookup时,只会找到最新的定义。
答案 2 :(得分:2)
首先要认识到Ruby 中没有内部或外部方法这样的东西。
您正在方法中定义一个新方法 - 在这种情况下,由于定义的方法与现有方法具有相同的名称,因此新定义将完全覆盖原始方法。
你拥有的东西相当于(或许)更明显:
class Example
def one
self.class.send(:define_method, :one) do
@value = 99
end
puts "Expensive Call"
@value = 99 # assume its expensive call
end
end
这里更清楚的是你在类的上下文中定义了一个方法。