【问题标题】:Using local variables in define_method在 define_method 中使用局部变量
【发布时间】:2015-08-13 05:32:13
【问题描述】:

我想了解define_method 的工作原理以及如何正确使用定义块之外的变量。这是我的代码:

class Test
  def self.plugin
    for i in 1..2
      define_method("test#{i}".to_sym) do
        p i
      end
    end
  end
  plugin
end

ob = Test.new
ob.test1 #=> 2  (I would expect 1)
ob.test2 #=> 2  (I would expect 2)

似乎在test1test2方法中,i的值在定义时没有被替换,而是在调用方法时直接当场计算。所以我们只看到i 的最新值,即2。但是 Ruby 是从哪里获取这个值的呢?有没有办法让test#{i} 打印i

在这种特殊情况下,我可以做一个workaround using __method__,但可能有更好的解决方案。

【问题讨论】:

  • closure 的力量在这里表达............ :)
  • 感谢您的链接,该问题解决了同样的问题。但我不确定那里是否提供了解决方案。至少有一个 cmets 不起作用:
    class Test for name in [ :new, :create, :destroy ] local_name = name define_method("test_#{local_name}") do puts local_name end end end ob = Test.new ob.test_new #=> 销毁(我希望是“新”) ob.test_create #=> 销毁(我希望是“新”)
  • 嗯.. 未标记。但这里是similar post
  • 我完全从您提到的similar post 中获取了代码(对不起标记)。只是想指出该解决方案仅在第二条评论中提出,它不起作用:-)
  • 我无法解析“...i 的值不是...”部分。

标签: ruby metaprogramming


【解决方案1】:

正如 cmets 中提到的,这归结为闭包 - 传递给 define_method 的块从其范围内捕获局部变量(而不仅仅是您发现的它们的值)。

for 不会创建新范围,因此您的方法“看到”对i 的更改。如果您使用一个块(例如每个块),则会创建一个新的范围,这不会发生。您只需要将代码更改为

class Test
  def self.plugin
    (1..2).each do |i|
      define_method("test#{i}".to_sym) do
        p i
      end
    end
  end
  plugin
end

这基本上就是 Arup 所链接的问题所涉及的内容

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 2020-10-11
    • 1970-01-01
    相关资源
    最近更新 更多