2011-04-05 9 views
5

Non riesco a ottenere una variabile da un ciclo for. Sembra che i (var) siano calcolati in seguito e non la definizione della classe che richiedo totalmente.define_method non utilizza le variabili finché non viene chiamato il metodo?

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 

Devo usare def? in tal caso, come posso ottenere i nomi dei metodi dinamici che ho ottenuto qui con def.

risposta

7

Che cosa sta succedendo c'è un po 'sottile ... il tradizionale ciclo for che stai usando condivide la singola variabile "i" attraverso tutte le iterazioni ... La chiusura (password di blocco per define_method) sta catturando "i" - e poiché c'è solo una "i", saranno tutti (alla fine del ciclo for) a catturare il valore finale di "i", che è l'ultimo valore dell'intervallo su cui stai eseguendo il ciclo.

Soluzione alternativa:

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> 

Edit: mi dispiace non ho il tempo per una spiegazione corretta, ma una rapida ricerca cresciuto un post in cui sarete in grado di ottenere l'essenza di esso: http://paulphilippov.com/articles/enumerableeach_vs_for_loops_in_ruby

2

Sebbene @ di RyanLeCompte risposta è migliore e più pulito (e descrive la causa del problema sufficientemente), ecco una soluzione alternativa, modellato dopo il modo in cui questo problema è in genere evitato in 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 

non accettare questa risposta, ma votano in su se ti aiuta a salire di livello il vostro metaprogrammazione. :)

Problemi correlati