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 @collection
NIIL 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 for
lus, leeft de iteratorvariabele nog steeds nadat het blok is voltooid. Met de each
lus, is dit niet, tenzij het al is gedefinieerd als een lokale variabele voordat de lus is gestart.
anders dan dat, for
is slechts syntaxisuiker voor de each
-methode.
Wanneer @collection
is nil
Beide 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 each
is 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 for
en while
, heeft de bloksyntaxis in het algemeen de voorkeur.
Een ander subtiel verschil is dat elke variabele die u in een for
lus 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 for
heeft een serieuze fout en mag niet worden gebruikt.
Hier is een voorbeeld waarbij for
een 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 for
lus wordt de variabele n
eenmalig gedefinieerd en dan wordt die ene definitie gebruikt voor alle iteraties. Vandaar dat elk blok verwijst naar dezelfde n
die een waarde heeft van quz
tegen de tijd dat de lus eindigt. Fout!
In een each
-lus wordt voor elke iteratie een nieuwe variabele n
gedefinieerd, bijvoorbeeld hierboven wordt de variabele n
drie verschillende keren gedefinieerd. Vandaar dat elk blok verwijst naar een aparte n
met de juiste waarden.
Antwoord 6
Het lijkt erop dat er geen verschil is, for
gebruikt each
eronder.
$ 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 a
gedefinieerd achter nadat de lus is voltooid. Waar zoals each
dat niet doet. Dat is nog een reden om each
te 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.