Ruby中的"for"vs"each"

mpo*_*z08 196 ruby iteration each foreach loops

我刚才有一个关于Ruby循环的快速问题.这两种迭代集合的方式有区别吗?

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

# way 2
for item in @collection
  # do whatever
end
Run Code Online (Sandbox Code Playgroud)

只是想知道这些是否完全一样,或者是否有一个微妙的差异(可能是什么时候@collection是零).

Jer*_*ten 306

这是唯一的区别:

每:

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
Run Code Online (Sandbox Code Playgroud)

对于:

irb> for x in [1,2,3]; end
  => [1, 2, 3]
irb> x
  => 3
Run Code Online (Sandbox Code Playgroud)

使用for循环,迭代器变量在块完成后仍然存在.随着each循环,这不,除非循环开始前它已经被定义为一个局部变量.

除此之外,这for只是该each方法的语法糖.

如果@collectionnil两个回路抛出一个异常:

例外:未定义的局部变量或main:Object的方法`@collection'

  • 有充分的理由为什么x保留在for情况下,还是这个不良设计:P?与大多数其他语言相比,这似乎很不直观。 (3认同)
  • @ cyc115 x保留在* for *场景中的原因是由于(通常而言)关键字没有创建新范围。* if *,*除非*,* begin *,* for *,* while *等都适用于当前范围。但是#each接受一个块。块始终在当前范围的顶部添加自己的范围。这意味着将无法从块外部访问在块中声明新变量(因此是新作用域),因为那里没有可用的附加作用域。 (2认同)

Chr*_*heD 43

请参阅" For循环的邪恶 "以获得一个很好的解释(考虑变量范围有一个小差异).

使用each认为是更惯用的Ruby使用.


Bay*_*del 29

你的第一个例子,

@collection.each do |item|
  # do whatever
end
Run Code Online (Sandbox Code Playgroud)

更惯用.虽然Ruby支持类似for和的循环结构while,但通常首选块语法.

另一个细微的区别是,您在for循环中声明的任何变量都将在循环外部可用,而迭代器块中的变量实际上是私有的.


Mr.*_*ack 6

另一个不同..

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 
Run Code Online (Sandbox Code Playgroud)

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

更清楚:http://www.ruby-forum.com/topic/179264#784884


aku*_*uhn 5

永远不要使用for它可能会导致几乎无法追踪的错误。

不要被愚弄,这与惯用代码或样式问题无关。Ruby 的实现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
Run Code Online (Sandbox Code Playgroud)

印刷

quz
quz
quz
Run Code Online (Sandbox Code Playgroud)

使用%w{foo bar quz}.each { |n| ... }打印

foo
bar
quz
Run Code Online (Sandbox Code Playgroud)

为什么?

for循环中,变量n仅定义一次,然后该定义用于所有迭代。因此,每个块都引用相同的块,在循环结束时其n值为quz。漏洞!

each循环中n,每次迭代都会定义一个新变量,例如上面的变量n被定义了三个不同的时间。因此,每个块都引用一个n具有正确值的单独块。