"for" vs "each" in Ruby

у меня просто был быстрый вопрос относительно циклов в Ruby. Есть ли разница между этими двумя способами перебора коллекции?

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

# way 2
for item in @collection
  # do whatever
end

просто интересно, являются ли они точно такими же или, может быть, есть тонкая разница (возможно, когда @collection равна нулю).

7 ответов


это единственная разница:

каждая:

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

для:

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

С for цикл, переменная итератора все еще живет после завершения блока. С each цикл, это не так, если он уже не был определен как локальная переменная до начала цикла.

кроме этого, for - это просто синтаксический сахар для each метод.

, когда @collection is nil обе петли исключение:

исключение: неопределенная локальная переменная или метод "@collection " для main: Object


в разделе "зло цикла For " для хорошего объяснения (есть одна небольшая разница, учитывая переменную область видимости).

С помощью each is считается более идиоматичным использование Ruby.


ваш первый пример,

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

более идиоматические. В то время как Ruby поддерживает циклические конструкции, такие как for и while синтаксис блока, как правило, предпочтительнее.

другое тонкое различие заключается в том, что любая переменная, которую вы объявляете в for цикл будет доступен вне цикла, в то время как внутри блока итератора фактически являются частными.


еще один разных..

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 

источник:http://paulphilippov.com/articles/enumerable-each-vs-for-loops-in-ruby

для более ясного: http://www.ruby-forum.com/topic/179264#784884


похоже, нет никакой разницы,for использует each внизу.

$ 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

как говорит Баярд, каждый более идиоматичен. Он скрывает от вас больше и не требует специальных языковых функций. согласно комментарию Телемаха

for .. in .. устанавливает итератор вне области цикла, поэтому

for a in [1,2]
  puts a
end

листья a определено после завершения цикла. Где each - нет. Что является еще одной причиной в пользу использования each, потому что переменная Temp живет более короткий срок.


никогда не используйте for это может приводить к ошибкам.

разница тонкая, но может вызвать огромные ошибки!

не обманывайтесь, это не об идиоматических проблемах кода или стиля. Это вопрос избежания почти неотслеживаемых ошибок в производственном коде. Реализация Рубина for имеет серьезный недостаток и не должен использоваться. Всегда используйте each петли, никогда не используйте for петли.

вот пример for вводит Жук,

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

печать

quz
quz
quz

используя %w{foo bar quz}.each { |n| ... } печать

foo
bar
quz

почему?

на for цикл переменной n определяется один раз и только, а затем это одно определение используется для всех итераций. Следовательно, каждый блок относится к одному и тому же n какое имеет значение quz к моменту окончания цикла. Жучок!

на each петля свежей переменной n определяется для каждой итерации, например выше переменная n определяется три раза. Следовательно, каждый блок относится к отдельному n с правильными значениями.


насколько я знаю, использование блоков вместо структур управления на языке более идиоматично.