“For” vs “each” in Ruby

Ho appena avuto una breve domanda riguardante i loop in Ruby. C’è una differenza tra questi due modi di iterare attraverso una collezione?

# way 1 @collection.each do |item| # do whatever end # way 2 for item in @collection # do whatever end 

Mi chiedo solo se sono esattamente uguali o se forse c’è una sottile differenza (probabilmente quando @collection è nullo).

Questa è l’unica differenza:

ogni:

 irb> [1,2,3].each { |x| } => [1, 2, 3] irb> x NameError: undefined local variable or method `x' for main:Object from (irb):2 from :0 

per:

 irb> for x in [1,2,3]; end => [1, 2, 3] irb> x => 3 

Con il ciclo for , la variabile iteratore vive ancora dopo che il blocco è terminato. Con each ciclo, non lo fa, a meno che non sia già stato definito come una variabile locale prima dell’avvio del ciclo.

Oltre a questo, for è solo lo zucchero di syntax per each metodo.

Quando @collection è nil entrambi i cicli generano un’eccezione:

Eccezione: variabile locale non definita o metodo `@collection ‘per main: Object

Vedi ” The Evils of the For ” per una buona spiegazione (c’è una piccola differenza considerando l’ambito della variabile).

L’utilizzo di each è considerato un uso più idiomatico di Ruby.

Il tuo primo esempio,

 @collection.each do |item| # do whatever end 

è più idiomatico Mentre Ruby supporta i costrutti di loop come for e while , la syntax del blocco è generalmente preferita.

Un’altra sottile differenza è che qualsiasi variabile dichiarata all’interno di un ciclo for sarà disponibile al di fuori del ciclo, mentre quelle all’interno di un blocco iteratore sono effettivamente private.

Un altro diverso ..

 number = ["one", "two", "three"] => ["one", "two", "three"] loop1 = [] loop2 = [] number.each do |c| loop1 << Proc.new { puts c } end => ["one", "two", "three"] for c in number loop2 << Proc.new { puts c } end => ["one", "two", "three"] loop1[1].call two => nil loop2[1].call three => nil 

fonte: http://paulphilippov.com/articles/enumerable-each-vs-for-loops-in-ruby

per ulteriori informazioni : http://www.ruby-forum.com/topic/179264#784884

Sembra che non ci siano differenze, for usi sotto.

 $ irb >> for x in nil >> puts x >> end NoMethodError: undefined method `each' for nil:NilClass from (irb):1 >> nil.each {|x| puts x} NoMethodError: undefined method `each' for nil:NilClass from (irb):4 

Come dice Bayard, ognuno è più idiomatico. Ti nasconde di più e non richiede caratteristiche linguistiche speciali. Commento di Per Telemachus

for .. in .. imposta l’iteratore al di fuori dell’ambito del ciclo, quindi

 for a in [1,2] puts a end 

lascia a definito dopo che il ciclo è finito. Dove come each non lo fa. Quale è un altro motivo a favore dell’utilizzo di each , perché la variabile temp vive un periodo più breve.

Mai e poi mai usare for questo potrebbe causare bug.

La differenza è sottile ma può causare tremendi bug!

Non farti ingannare, non si tratta di codice idiomatico o di problemi di stile. Si tratta di evitare bug quasi irreperibili nel codice di produzione. L’implementazione di for Ruby ha un grave difetto e non dovrebbe essere utilizzata. Usa sempre i loop, non usare mai for loop.

Ecco un esempio in cui for introdurre un bug,

 class Library def initialize @ary = [] end def method_with_block(&block) @ary << block end def method_that_uses_these_blocks @ary.map(&:call) end end lib = Library.new for n in %w{foo bar quz} lib.method_with_block { n } end puts lib.method_that_uses_these_blocks 

stampe

 quz quz quz 

Usando %w{foo bar quz}.each { |n| ... } %w{foo bar quz}.each { |n| ... } stampe

 foo bar quz 

Perché?

In un ciclo for la variabile n viene definita una sola volta e quindi quella definizione viene utilizzata per tutte le iterazioni. Quindi ogni blocco si riferisce allo stesso n che ha un valore di quz per il tempo in cui termina il ciclo. Bug!

In each ciclo una nuova variabile n è definita per ogni iterazione, per esempio sopra la variabile n è definita tre volte separate. Quindi ogni blocco si riferisce ad un n separato con i valori corretti.

Per quanto ne so, l’uso di blocchi anziché di strutture di controllo linguistiche è più idiomatico.