Much of programming is concerned with repetition. Maybe you want your program to beep 10 times, read lines from a file as long as there are more lines to read, or display a warning until the user presses a key. Ruby provides a number of ways of performing this kind of repetition.
In many programming languages, when you want to run a bit of code a certain number of times, you can just put it inside a for
loop. In most languages, you give a for
loop a variable initialized with a starting value that is incremented by 1 on each turn through the loop until it meets some specific ending value. When the ending value is met, the for
loop stops running.
Here’s a version of this traditional type of for
loop written in Pascal:
(* This is Pascal code, not Ruby! *) for i := 1 to 3 do writeln( i );
You may recall from the previous chapter that Ruby’s for
loop doesn’t work like this at all! Instead of giving it starting and ending values, you give the for
loop a list of items, and it iterates over them, one by one, assigning each value in turn to a loop variable until it gets to the end of the list.
For example, here is a for
loop that iterates over the items in an array, displaying each in turn:
for_loop.rb
# This is Ruby code... for i in [1,2,3] do puts( i ) end
The for
loop is more like the “for each” iterator provided by some other programming languages. The items over which the loop iterates don’t have to be integers. This works just as well:
for s in ['one','two','three'] do puts( s ) end
The author of Ruby describes for
as “syntax sugar” for the each
method, which is implemented by collection types such as Arrays, Sets, Hashes, and Strings (a String being, in effect, a collection of characters). For the sake of comparison, this is one of the for
loops shown earlier rewritten using the each
method:
each_loop.rb
[1,2,3].each do |i| puts( i ) end
As you can see, there isn’t really all that much difference. To convert the for
loop to an each
iterator, all I’ve had to do is delete for
and in
and append .each
to the array. Then I’ve put the iterator variable, i
, between a pair of upright bars after do
. Compare these other examples to see just how similar for
loops are to each
iterators.
for_each.rb
# --- Example 1 --- # i) for for s in ['one','two','three'] do puts( s ) end # ii) each ['one','two','three'].each do |s| puts( s ) end # --- Example 2 --- # i) for for x in [1, "two", [3,4,5] ] do puts( x ) end # ii) each [1, "two", [3,4,5] ].each do |x| puts( x ) end
Note, incidentally, that the do
keyword is optional in a for
loop that spans multiple lines, but it is obligatory when it is written on a single line:
# Here the 'do' keyword can be omitted for s in ['one','two','three'] puts( s ) end # But here it is required for s in ['one','two','three'] do puts( s ) end
This example shows how both for
and each
can be used to iterate over the values in a range:
for_each2.rb
# for for s in 1..3 puts( s ) end # each (1..3).each do |s| puts(s) end
for_to.rb
Note, incidentally, that a range expression such as 1..3
must be enclosed between parentheses when used with the each
method, or Ruby assumes you are attempting to use each
as a method of the final integer (a Fixnum) rather than of the entire expression (a Range). The parentheses are optional when a range is used in a for
loop.
3.145.39.60