define_method在调用方法之前不使用变量?

时间:2011-04-05 15:58:27

标签: ruby-on-rails ruby

我无法从for循环中获取变量。似乎i(var)是后来计算的,而不是我完全需要的类定义。

ree-1.8.7-2010.02 > class Pat
ree-1.8.7-2010.02 ?>  for i in 39..47
ree-1.8.7-2010.02 ?>    define_method("a#{i}".to_sym) do
ree-1.8.7-2010.02 >         puts i 
ree-1.8.7-2010.02 ?>      end
ree-1.8.7-2010.02 ?>    end
ree-1.8.7-2010.02 ?>  end
#=> 39..47 

ree-1.8.7-2010.02 > p = Pat.new
#=> #<Pat:0x103c31140> 

ree-1.8.7-2010.02 > p.a39
47
#=> nil 

ree-1.8.7-2010.02 > p.a49
NoMethodError: undefined method `a49' for #<Pat:0x103c31140>
    from (irb):69
    from :0
ree-1.8.7-2010.02 > p.a40
47
#=> nil 

我应该使用def吗?如果是这样,我怎样才能实现我在这里用def。

实现的动态方法名称

3 个答案:

答案 0 :(得分:7)

正在发生的事情有点微妙......你正在使用的传统for循环在所有迭代中共享单个“i”变量......闭包(对于define_method的块密码)正在捕获“i” - 和因为只有一个“i”,所以它们(在for循环结束时)将捕获“i”的最终值,这是你循环的范围中的最后一个值。

替代解决方案:

class C
  (1..10).each {|i| define_method("a#{i}") { puts i } }
end

答案 1 :(得分:3)

>> class Pat
..   (37..47). each do |i|
..       define_method("a#{i}".to_sym) do
..         puts i
..       end
..     end
..   end #=> 37..47
>> Pat.new.a40 #=> nil
40
>> Pat.new.a50
NoMethodError: undefined method `a50' for #<Pat:0x00000100b39bc8>

编辑:抱歉,我没有时间进行正确的解释,但快速搜索了一篇博文,您将能够得到它的要点:http://paulphilippov.com/articles/enumerableeach_vs_for_loops_in_ruby

答案 2 :(得分:2)

尽管@ RyanLeCompte的答案更好,更清晰(并且充分描述了问题的原因),但这里有一个替代解决方案,在JavaScript中通常避免此问题的方式后形成:

class Foo
  for i in 1..9 do
    define_method "a#{i}", &(lambda{|x| lambda{puts x}})[i]
  end
end
Foo.new.a1
#=> 1
Foo.new.a9
#=> 9

不接受这个答案,但如果它可以帮助你升级元编程,那就投票吧。 :)