define_method не использует переменные, пока метод не вызван? - PullRequest
5 голосов
/ 05 апреля 2011

У меня проблемы с получением переменной из цикла 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 ]

7 голосов
/ 05 апреля 2011

То, что происходит там, немного тонко ... традиционный цикл for, который вы используете, разделяет одну переменную "i" на всех итерациях ... Закрытие (пароль блока для define_method) захватывает "i" - и поскольку существует только одно «i», все они (в конце цикла for) фиксируют окончательное значение «i», которое является последним значением в диапазоне, над которым вы зацикливаетесь.

Альтернативное решение:

class C
  (1..10).each {|i| define_method("a#{i}") { puts i } }
end
3 голосов
/ 05 апреля 2011
>> 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 голосов
/ 05 апреля 2011

Хотя ответ @ 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

Не принимайте этот ответ, но проголосуйте, если он поможет повысить уровень вашего метапрограммирования. :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...