“voor” vs “elk” in Ruby

Ik had gewoon een snelle vraag met betrekking tot lussen in Ruby. Is er een verschil tussen deze twee manieren van iterating via een verzameling?

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

Ik vraag me gewoon af of dit precies hetzelfde zijn of als er misschien een subtiel verschil is (mogelijk wanneer @collectionNIIL is).


Antwoord 1, Autoriteit 100%

Dit is het enige verschil:

elk:

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

voor:

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

Met de forlus, leeft de iteratorvariabele nog steeds nadat het blok is voltooid. Met de eachlus, is dit niet, tenzij het al is gedefinieerd als een lokale variabele voordat de lus is gestart.

anders dan dat, foris slechts syntaxisuiker voor de each-methode.

Wanneer @collectionis nilBeide lussen gooien een uitzondering:

Uitzondering: undefined lokale variabele of methode `@collection ‘voor main: object


Antwoord 2, Autoriteit 15%

Zie “het kwaad van de voor lus “Voor een goede uitleg (er is een klein verschil gezien variabele scoping).

Gebruik eachis beschouwd als meer idiomatisch Gebruik van Ruby.


Antwoord 3, Autoriteit 10%

Uw eerste voorbeeld,

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

is meer idiomatisch . Terwijl Ruby ondersteunt lusvormen zoals foren while, heeft de bloksyntaxis in het algemeen de voorkeur.

Een ander subtiel verschil is dat elke variabele die u in een forlus declareert, buiten de lus beschikbaar zal zijn, terwijl die binnen een iteratorblok effectief privé zijn.


Antwoord 4, Autoriteit 2%

Nog een ander ..

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 

Bron: http://paulphilippov.com/articles/ Toezichtwaardige-ellende-vs-voor-lussen-in-ruby

Want meer duidelijk: http://www.ruby-forum.com/topic/ 179264 # 784884


Antwoord 5, Autoriteit 2%

Gebruik nooit for, het kan bijna ontraceerbare bugs veroorzaken.

Laat u niet misleiden, dit gaat niet over idiomatische code of stijlproblemen. Ruby’s implementatie van forheeft een serieuze fout en mag niet worden gebruikt.

Hier is een voorbeeld waarbij foreen bug introduceert,

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

Afdrukken

quz
quz
quz

Gebruik %w{foo bar quz}.each { |n| ... }afdrukken

foo
bar
quz

Waarom?

In een forlus wordt de variabele neenmalig gedefinieerd en dan wordt die ene definitie gebruikt voor alle iteraties. Vandaar dat elk blok verwijst naar dezelfde ndie een waarde heeft van quztegen de tijd dat de lus eindigt. Fout!

In een each-lus wordt voor elke iteratie een nieuwe variabele ngedefinieerd, bijvoorbeeld hierboven wordt de variabele ndrie verschillende keren gedefinieerd. Vandaar dat elk blok verwijst naar een aparte nmet de juiste waarden.


Antwoord 6

Het lijkt erop dat er geen verschil is, forgebruikt eacheronder.

$ 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

Zoals Bayard zegt, elk is meer idiomatisch. Het verbergt meer voor u en vereist geen speciale taalfuncties.
Op commentaar van Telemachus

for .. in ..zet de iterator buiten het bereik van de lus, dus

for a in [1,2]
  puts a
end

laat agedefinieerd achter nadat de lus is voltooid. Waar zoals eachdat niet doet. Dat is nog een reden om eachte gebruiken, omdat de tijdelijke variabele een kortere periode heeft.


Antwoord 7

Voor zover ik weet, is het gebruik van blokken in plaats van in-taal controlestructuren meer idiomatisch.


Antwoord 8

Ik wil alleen een specifiek punt maken over de for in-lus in Ruby. Het lijkt misschien een constructie die lijkt op andere talen, maar in feite is het een uitdrukking zoals elke andere lusconstructie in Ruby. In feite werkt de for in met Enumerable-objecten net als elke iterator.

De verzameling die wordt doorgegeven aan for in kan elk object zijn met een elke iteratormethode. Arrays en hashes definiëren elke methode, en veel andere Ruby-objecten doen dat ook. De for/in-lus roept de elke methode van het opgegeven object aan. Aangezien die iterator waarden oplevert, wijst de for-lus elke waarde (of elke reeks waarden) toe aan de gespecificeerde variabele (of variabelen) en voert vervolgens de code in de body uit.

Dit is een dwaas voorbeeld, maar illustreert het punt dat de for in-lus werkt met ELK object dat een each-methode heeft, net zoals elke iterator dat doet:

class Apple
  TYPES = %w(red green yellow)
  def each
    yield TYPES.pop until TYPES.empty?
  end
end
a = Apple.new
for i in a do
  puts i
end
yellow
green
red
=> nil

En nu de elke iterator:

a = Apple.new
a.each do |i|
  puts i
end
yellow
green
red
=> nil

Zoals je kunt zien, reageren beide op elke methode die waarden teruggeeft aan het blok. Zoals iedereen hier al zei, verdient het absoluut de voorkeur om elke iterator te gebruiken boven de for in-lus. Ik wilde alleen maar naar huis rijden met het punt dat er niets magisch is aan de for-in-lus. Het is een uitdrukking die elke methode van een verzameling aanroept en deze vervolgens doorgeeft aan het codeblok. Daarom is het een zeer zeldzaam geval dat u zou moeten gebruiken voor in. Gebruik bijna altijd elke iterator (met het extra voordeel van blokbereik).


Antwoord 9

(1..4).each { |i| 
  a = 9 if i==3
  puts a 
}
#nil
#nil
#9
#nil
for i in 1..4
  a = 9 if i==3
  puts a
end
#nil
#nil
#9
#9

In de ‘for’-lus is de lokale variabele nog steeds actief na elke lus. In ‘elke’ lus wordt de lokale variabele na elke lus vernieuwd.

Other episodes