提问人:mportiz08 提问时间:7/21/2010 最后编辑:the Tin Manmportiz08 更新时间:11/17/2023 访问量:282715
Ruby 中的“for”与“each”
"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
答:
你的第一个例子,
@collection.each do |item|
# do whatever
end
更惯用。虽然Ruby支持像和这样的循环结构,但块语法通常是首选。for
while
另一个微妙的区别是,您在循环中声明的任何变量都将在循环之外可用,而迭代器块中的变量实际上是私有的。for
评论
while
并且实际上有一些非常具体的用途,无法用每个用途代替,例如生成唯一值或用于 REPL。until
据我所知,使用块而不是语言控制结构更习惯。
看起来没有区别,在下面使用。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
就像贝亚德说的,每个都更惯用。它对你隐藏了更多,不需要特殊的语言功能。根据 Telemachus 的评论
for .. in ..
将迭代器设置在循环范围之外,因此
for a in [1,2]
puts a
end
在循环完成后定义。哪里没有。这是赞成使用 的另一个原因,因为 temp 变量的寿命较短。a
each
each
评论
for
each
请参阅“For 循环的弊端”以获得一个很好的解释(考虑到变量范围,有一个小差异)。
使用被认为是 Ruby 的惯用用法。each
评论
这是唯一的区别:
每:
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
nil
异常:main:Object 的未定义局部变量或方法“@collection”
评论
x
#each
each
还有一个区别:
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
不要被愚弄,这与惯用的代码或风格问题无关。Ruby 的实现存在严重缺陷,不应使用。for
下面是一个引入 bug 的示例,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
我只想对 Ruby 中的 for in 循环提出一个具体的观点。它可能看起来像一个类似于其他语言的构造,但实际上它是一个表达式,就像 Ruby 中所有其他循环构造一样。事实上,for in 与每个迭代器一样适用于 Enumerable 对象。
传递给 for in 的集合可以是具有 each 迭代器方法的任何对象。数组和哈希定义了每个方法,许多其他 Ruby 对象也是如此。for/in 循环调用指定对象的 each 方法。当该迭代器生成值时,for 循环将每个值(或每组值)分配给指定的一个或多个变量,然后执行 body 中的代码。
这是一个愚蠢的例子,但说明了 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
现在每个迭代器:
a = Apple.new
a.each do |i|
puts i
end
yellow
green
red
=> nil
正如你所看到的,两者都在响应每个方法,从而将值返回到块。正如这里的每个人所说,使用每个迭代器绝对比使用 for in 循环更可取。我只是想强调一点,即 for in 循环并没有什么神奇之处。它是一个表达式,它调用集合的每个方法,然后将其传递给其代码块。因此,这是一个非常罕见的情况,您需要将其用于 in。几乎总是使用每个迭代器(具有块范围的额外好处)。
(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”循环中,局部变量在每个循环后刷新。
评论