for 循环

在许多编程语言中,当你想将一些代码运行一定的次数时你可以把它放在 for 循环中。在大多数语言中,为 for 循环可以提供一个初始化的变量作为起始值,该起始值在每个循环中递增 1,循环到直到它满足某个特定的结束值。当满足结束值时,for 循环停止运行。这是用 Pascal 写的常规类型的 for 循环:

  1. (* This is Pascal code, not Ruby! *)
  2. for i := 1 to 3 do
  3. writeln( i );
for_loop.rb

您可能还记得上一章中 Ruby 的 for 循环根本不是这样的!我们会给 for 循环一个元素列表,而不是一个起始值和结束值,然后逐个迭代它们,将每个元素值依次分配给一个循环变量,直到它到达列表的末尾。

例如,这是一个 for 循环,它迭代数组中的项目,并依次显示:

  1. # This is Ruby code…
  2. for i in [1,2,3] do
  3. puts( i )
  4. end

for循环更像是其它编程语言中提供的 ‘for each’ 迭代器。循环迭代的项目不必是整数(integers)。这也可以…

  1. for s in ['one','two','three'] do
  2. puts( s )
  3. end

Ruby 的作者描述 for 循环是集合类型,例如 Arrays、Sets、Hashes 和 Strings(字符串实际上是一个字符集合)中实现的 each 方法的语法糖(syntax sugar)。为了便于比较,这是上面的 for 循环使用 each 方法进行重写的:

each_loop.rb
  1. [1,2,3].each do |i|
  2. puts( i )
  3. end

正如你所看到的,并没有太大的区别。要将 for循环转换为 each 迭代器,所要做的就是删除 forin,并将 .each 附加到数组中。然后把迭代变量 i 放在 do 后的两条竖线中。比较一下其它示例,看看 for 循环和 each 迭代器的相似程度:

for_each.rb
  1. # --- Example 1 ---
  2. # i) for
  3. for s in ['one','two','three'] do
  4. puts( s )
  5. end
  6. # ii) each
  7. ['one','two','three'].each do |s|
  8. puts( s )
  9. end
  10. # --- Example 2 ---
  11. # i) for
  12. for x in [1, "two", [3,4,5] ] do puts( x ) end
  13. # ii) each
  14. [1, "two", [3,4,5] ].each do |x| puts( x ) end

顺便提一下,请注意,do 关键字在跨越多行的 for 循环中是可选的,但是当它写在一行上时是必须的:

  1. # Here the "do" keyword can be omitted
  2. for s in ['one','two','three']
  3. puts( s )
  4. end
  5. # But here it is required
  6. for s in ['one','two','three'] do puts( s ) end
for_to.rb

如何编写一个“普通(normal)”的 for 循环…

如果你习惯了常规类型的 for 循环,你可以随时通过使用 Ruby 中的 for 循环迭代范围中的值来实现。例如,这显示了如何使用一个 for 循环变量从 1 到 10 计数,并在每次循环过程中显示其值: for i in (1..10) do puts( i ) end
for_each2.rb

此示例显示了 foreach 两者如何用于迭代范围内的值:

  1. # for
  2. for s in 1..3
  3. puts( s )
  4. end
  5. # each
  6. (1..3).each do |s|
  7. puts(s)
  8. end

顺便提一下,要注意在使用 each 方法时,范围(range)表达式,例如 1..3 必须使用圆括号包围,否则 Ruby 会假设你试图使用整数(一个 Fixnum)作为 each 方法的最终值,而不是整个表达式(范围,Range)。range 用在 for 循环中时圆括号是可选的。