我有一个关于Ruby循环的问题。这两种遍历集合的方法有区别吗?
# way 1
@collection.each do |item|
# do whatever
end
# way 2
for item in @collection
# do whatever
end
只是想知道这些是否完全相同,或者是否可能有细微的差异(可能在@collection为nil时)。
我有一个关于Ruby循环的问题。这两种遍历集合的方法有区别吗?
# way 1
@collection.each do |item|
# do whatever
end
# way 2
for item in @collection
# do whatever
end
只是想知道这些是否完全相同,或者是否可能有细微的差异(可能在@collection为nil时)。
当前回答
永远不要使用,因为它可能会导致几乎不可追踪的bug。
不要被愚弄了,这不是关于惯用代码或风格的问题。Ruby的for实现有一个严重的缺陷,不应该使用。
下面是一个for引入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
打印
quz
quz
quz
使用%w{foo bar quz}。每个{|n|…}打印
foo
bar
quz
Why?
在for循环中,变量n定义一次且仅一次,然后该定义将用于所有迭代。因此,在循环结束时,每个块都指向相同的n,其值为quz。错误!
在每个循环中,每次迭代都定义一个新的变量n,例如上面的变量n定义了三次。因此,每个块都指向一个单独的具有正确值的n。
其他回答
请参阅“For循环的弊端”以获得更好的解释(考虑到变量作用域,有一个小区别)。
使用这两种都被认为是Ruby更习惯的用法。
这是唯一的区别:
每一个:
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
for:
irb> for x in [1,2,3]; end
=> [1, 2, 3]
irb> x
=> 3
对于for循环,迭代器变量在块完成后仍然存在。对于每个循环,它都不会,除非它在循环开始之前已经定义为局部变量。
除此之外,for只是每个方法的语法糖。
当@collection为nil时,两个循环都会抛出异常:
异常:main:Object未定义的局部变量或方法“@collection”
(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
在for循环中,局部变量在每次循环后仍然有效。在“each”循环中,局部变量在每次循环后都会刷新。
我只是想特别说明一下Ruby中的for in循环。它看起来像是一个类似于其他语言的构造,但实际上它是一个像Ruby中其他循环构造一样的表达式。事实上,for In与Enumerable对象的作用就像each迭代器一样。
传递给for in的集合可以是任何具有each迭代器方法的对象。数组和散列定义了每个方法,许多其他Ruby对象也是如此。for/in循环调用指定对象的每个方法。当迭代器生成值时,for循环将每个值(或每一组值)赋给指定的变量(或多个变量),然后执行代码体。
这是一个愚蠢的例子,但说明了for in循环适用于具有each方法的ANY对象,就像each迭代器一样:
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
现在是each迭代器:
a = Apple.new
a.each do |i|
puts i
end
yellow
green
red
=> nil
As you can see, both are responding to the each method which yields values back to the block. As everyone here stated, it is definitely preferable to use the each iterator over the for in loop. I just wanted to drive home the point that there is nothing magical about the for in loop. It is an expression that invokes the each method of a collection and then passes it to its block of code. Hence, it is a very rare case you would need to use for in. Use the each iterator almost always (with the added benefit of block scope).
据我所知,使用块而不是语言内的控制结构更习惯。