“为了”与“每个”在红宝石中

发布于 2024-09-10 13:03:29 字数 247 浏览 9 评论 0原文

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

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

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

只是想知道它们是否完全相同,或者是否存在细微的差异(可能当 @collection 为零时)。

I just had a quick question regarding loops in Ruby. Is there a difference between these two ways of iterating through a collection?

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

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

Just wondering if these are exactly the same or if maybe there's a subtle difference (possibly when @collection is nil).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

╭ゆ眷念 2024-09-17 13:03:29

这是唯一的区别:

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

for:

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

使用 for 循环,迭代器变量在块完成后仍然存在。对于 each 循环,则不会,除非它在循环开始之前已被定义为局部变量。

除此之外,for 只是 each 方法的语法糖。

当 @collection 为 nil 时,两个循环都会抛出异常:

异常:main:Object 的未定义局部变量或方法“@collection”

This is the only difference:

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

for:

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

With the for loop, the iterator variable still lives after the block is done. With the each loop, it doesn't, unless it was already defined as a local variable before the loop started.

Other than that, for is just syntax sugar for the each method.

When @collection is nil both loops throw an exception:

Exception: undefined local variable or method `@collection' for main:Object

樱花细雨 2024-09-17 13:03:29

请参阅“For 循环的弊端”了解详情很好的解释(考虑到变量范围有一个小小的差异)。

使用 each 被认为更惯用使用红宝石。

See "The Evils of the For Loop" for a good explanation (there's one small difference considering variable scoping).

Using each is considered more idiomatic use of Ruby.

汹涌人海 2024-09-17 13:03:29

您的第一个示例

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

更惯用。虽然 Ruby 支持像 forwhile 这样的循环结构,但块语法通常是首选。

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

Your first example,

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

is more idiomatic. While Ruby supports looping constructs like for and while, the block syntax is generally preferred.

Another subtle difference is that any variable you declare within a for loop will be available outside the loop, whereas those within an iterator block are effectively private.

提笔落墨 2024-09-17 13:03:29

永远不要使用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

进行打印

quz
quz
quz

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

foo
bar
quz

为什么?

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

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

Never ever use for it may cause almost untraceable bugs.

Don't be fooled, this is not about idiomatic code or style issues. Ruby's implementation of for has a serious flaw and should not be used.

Here is an example where for introduces a 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

Prints

quz
quz
quz

Using %w{foo bar quz}.each { |n| ... } prints

foo
bar
quz

Why?

In a for loop the variable n is defined once and only and then that one definition is use for all iterations. Hence each blocks refer to the same n which has a value of quz by the time the loop ends. Bug!

In an each loop a fresh variable n is defined for each iteration, for example above the variable n is defined three separate times. Hence each block refer to a separate n with the correct values.

十年不长 2024-09-17 13:03:29

还有一个区别:

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

One more difference:

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 

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

for more clear: http://www.ruby-forum.com/topic/179264#784884

毁虫ゝ 2024-09-17 13:03:29

看起来没有什么区别,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

在循环完成后保留 a 定义。而 each 则不然。这是使用 each 的另一个原因,因为 temp 变量的生存期较短。

It looks like there is no difference, for uses each underneath.

$ 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

Like Bayard says, each is more idiomatic. It hides more from you and doesn't require special language features.
Per Telemachus's Comment

for .. in .. sets the iterator outside the scope of the loop, so

for a in [1,2]
  puts a
end

leaves a defined after the loop is finished. Where as each doesn't. Which is another reason in favor of using each, because the temp variable lives a shorter period.

書生途 2024-09-17 13:03:29
(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”循环中,局部变量在每次循环后刷新。

(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 'for' loop, local variable is still lives after each loop. In 'each' loop, local variable refreshes after each loop.

过度放纵 2024-09-17 13:03:29

据我所知,使用块而不是语言内控制结构更惯用。

As far as I know, using blocks instead of in-language control structures is more idiomatic.

杀お生予夺 2024-09-17 13:03:29

我只想就 Ruby 中的 for in 循环提出一个具体观点。它可能看起来像一个与其他语言类似的构造,但实际上它是一个与 Ruby 中所有其他循环构造类似的表达式。事实上,for in 就像each迭代器一样适用于Enumerable对象。

传递给 for in 的集合可以是具有 every 迭代器方法的任何对象。数组和散列定义了each 方法,许多其他Ruby 对象也定义了each 方法。 for/in 循环调用指定对象的each 方法。当迭代器产生值时,for 循环将每个值(或每组值)分配给指定的变量(或多个变量),然后执行主体中的代码。

这是一个愚蠢的例子,但说明了 for in 循环适用于任何具有each方法的对象,就像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

如您所见,两者都响应each将值返回给块的方法。正如这里每个人所说,使用每个迭代器绝对比使用 for in 循环更可取。我只是想强调一点:for in 循环并没有什么神奇之处。它是一个调用集合的each 方法然后将其传递给其代码块的表达式。因此,在极少数情况下您需要使用 for in。几乎总是使用 every 迭代器(还有块作用域的额外好处)。

I just want to make a specific point about the for in loop in Ruby. It might seem like a construct similar to other languages, but in fact it is an expression like every other looping construct in Ruby. In fact, the for in works with Enumerable objects just as the each iterator.

The collection passed to for in can be any object that has an each iterator method. Arrays and hashes define the each method, and many other Ruby objects do, too. The for/in loop calls the each method of the specified object. As that iterator yields values, the for loop assigns each value (or each set of values) to the specified variable (or variables) and then executes the code in body.

This is a silly example, but illustrates the point that the for in loop works with ANY object that has an each method, just like how the each iterator does:

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

And now the each iterator:

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).

浊酒尽余欢 2024-09-17 13:03:29

当使用 Ruby 的异步时,这一点非常重要。

require 'async'

Async do
  for i in 5.times do
    Async do
      sleep(1)
      print(i.to_s + " ")
    end
  end
end

将返回:4 4 4 4 4,因为 i 不会为每次迭代重新定义。

require 'async'

Async do
  5.times.each do |i|
    Async do
      sleep(1)
      print(i.to_s + " ")
    end
  end
end

将返回:0 1 2 3 4,因为i仅存在于其迭代块的范围内。

在阅读其他答案时,其原因变得相当明显,但由于在线搜索查询中的异步问题不会返回任何提及此问题的结果,因此我将这个答案留在这里。

请勿将for .. in ..async结合使用!

This is very important when using Ruby's async.

require 'async'

Async do
  for i in 5.times do
    Async do
      sleep(1)
      print(i.to_s + " ")
    end
  end
end

Will return: 4 4 4 4 4 as i is not re-defined for every iteration.

require 'async'

Async do
  5.times.each do |i|
    Async do
      sleep(1)
      print(i.to_s + " ")
    end
  end
end

Will return: 0 1 2 3 4 as i only ever lives inside the scope of its iteration's block.

The reason for this becomes fairly obvious when reading the other answers, but since online searches for this kind of problem with async in the query don't return any results mentioning this I left this answer here.

Do not use for .. in .. in conjunction with async!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文