2011-04-05 3 views
5

forループから変数を取得できません。私は完全に必要なクラス定義ではなく、i(var)が後で計算されるようです。define_methodはメソッドが呼び出されるまで変数を使用しませんか?

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でここで達成した動的メソッド名をどうやって達成できますか?

答えて

7

何が起こっています少し微妙です...あなたが使用している従来のforループは、すべての反復で1つの "i"変数を共有しています...閉包(define_methodへのブロックパスワード)は "i"をキャプチャしています。 "i"は、ループの最後に "i"の最終値を取り込みます(forループの最後にあります)。

代替ソリューション:

class C 
    (1..10).each {|i| define_method("a#{i}") { puts i } } 
end 
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

@ 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 

この回答を受け入れてはいけないが、それはあなたがあなたのメタプログラミングをレベルアップに役立ちます場合はそれを投票します。 :)

関連する問題