我一直在尝试在Ruby 1.9中动态定义一些实例方法。这是我用来尝试这个的代码:
class Testing
[:one, :two].each do |name|
define_method(name) do
puts __method__
end
end
end
这是输出:
ruby-1.9.2-p180 :008 > t = Testing.new
=> #<Testing:0x00000100961878>
ruby-1.9.2-p180 :009 > t.one
two
=> nil
ruby-1.9.2-p180 :010 > t.two
two
=> nil
ruby-1.9.2-p180 :011 >
我希望结果分别为one
和two
。如果我在迭代之外调用每个define_method
,它会按预期工作。我在这里不理解什么?
以下是我在网上看到的在迭代中调用define_method的众多示例之一。 Dynamically defined setter methods using define_method?
缺少什么?
另外:使用__method__
对我来说并不重要,但这是我展示的最佳方式,似乎只有发送到define_method
的最后一个块被用于定义的方法。也许这开始向我解释问题,但我仍然不明白..
答案 0 :(得分:3)
很好的发现奇怪的行为。在我测试的所有红宝石中,只有MRI 1.9.2证明了这一点。
Ryan Davis reported the bug on the ruby-core list(参考此问题)。
答案 1 :(得分:0)
您可以使用此类内容而非define_method
:
class Testing
[:one, :two].each do |name|
eval <<-EOM
def #{name}
puts __method__
end
EOM
end
end
t = Testing.new
t.one #=> "one"
t.two #=> "two"
答案 2 :(得分:0)
发生这种情况的原因是define_method以与def相比稍微不同的方式定义方法。它与创建匿名触发器和lambda有关。我建议只是使用方法名称,因为你已经拥有它。这应该避免必须在堆栈跟踪中搜索方法名称,因此它应该执行得更好:
class Testing
[:one, :two].each do |name|
define_method name do
"This method's name is #{name}."
end
end
end
Testing.new.one
=> This method's name is one.
Testing.new.two
=> This method's name is two.
要澄清,请注意以下两个陈述返回的内容:
class Testing
define_method :one do
__method__
end
end
=> #<Proc:0x000001009ebfc8@(irb):54 (lambda)>
class Testing
def one
__method__
end
end
=> nil
P.S:使用这两种格式之间也存在性能差异。您可以使用Benchmark验证自己def的速度比define_method快。