Loops

This section documents Ruby’s simple looping statements: while, until, and for. Ruby also includes the ability to define custom looping constructs known as iterators. Iterators (see Iterators and Enumerable Objects) are probably more commonly used than Ruby’s built-in looping statements; they are documented later in this chapter.

while and until

Ruby’s basic looping statements are while and until. They execute a chunk of code while a certain condition is true, or until the condition becomes true. For example:

x = 10               # Initialize a loop counter variable
while x >= 0 do      # Loop while x is greater than or equal to 0
  puts x             #   Print out the value of x
  x = x - 1          #   Subtract 1 from x
end                  # The loop ends here

# Count back up to 10 using an until loop
x = 0                # Start at 0 (instead of -1)
until x > 10 do      # Loop until x is greater than 10
  puts x
  x = x + 1
end                  # Loop ends here

The loop condition is the Boolean expression that appears between the while or until and do keywords. The loop body is the Ruby code that appears between the do and the end keyword. The while loop evaluates its condition. If the value is anything other than false or nil, it executes its body, and then loops to evaluate its condition again. In this way, the body is executed repeatedly, zero or more times, while the condition remains true (or, more strictly, non-false and non-nil).

The until loop is the reverse. The condition is tested and the body is executed if the condition evaluates to false or nil. This means that the body is executed zero or more times while the condition is false or nil. Note that any until loop can be converted to a while simply by negating the condition. Most programmers are familiar with while loops, but many have not used until loops before. For this reason, you may want to use while loops except when until truly improves the clarity of your code.

The do keyword in a while or until loop is like the then keyword in an if statement: it may be omitted altogether as long as a newline (or semicolon) appears between the loop condition and the loop body.[*]

while and until As Modifiers

If the body of a loop is a single Ruby expression, you can express that loop in a particularly compact form by using while or until as a modifier after the expression. For example:

x = 0                          # Initialize loop variable
puts x = x + 1 while x < 10    # Output and increment in a single expression

This modifier syntax uses the while keyword itself to separate the loop body from the loop condition, and avoids the need for the do (or newline) and end keywords. Contrast this code with the more traditional while loop written on a single line:

x = 0
while x < 10 do puts x = x + 1 end

until can be used as a modifier just as while can be:

a = [1,2,3]                 # Initialize an array
puts a.pop until a.empty?   # Pop elements from array until empty

Note that when while and until are used as modifiers, they must appear on the same line as the loop body that they modify. If there is a newline between the loop body and the while or until keyword, the Ruby interpreter will treat the loop body as an unmodified expression and the while or until as the beginning of a regular loop.

When while and until are used as modifiers for a single Ruby expression, the loop condition is tested first, even though it is written after the loop body. The loop body is executed zero or more times, just as if it were formatted as a regular while or until loop.

There is a special-case exception to this rule. When the expression being evaluated is a compound expression delimited by begin and end keywords, then the body is executed first before the condition is tested:

x = 10              # Initialize loop variable
begin               # Start a compound expression: executed at least once
  puts x            #   output x
  x = x - 1         #   decrement x
end until x == 0    # End compound expression and modify it with a loop

This results in a construct much like the do/while loop of C, C++, and Java. Despite its similarity to the do/while loop of other languages, this special-case behavior of loop modifiers with the begin statement is counterintuitive and its use is discouraged. Future releases of Ruby may forbid the use of while and until modifiers with begin/end.

Note that if you group multiple statements with parentheses and apply an until modifier to that grouped expression, you do not get this special case behavior:

x = 0               # Initialize loop variable
(                   # Start a compound expression: may be executed 0 times
  puts x            #   output x
  x = x - 1         #   decrement x
) until x == 0      # End compound expression and modify it with a loop

The for/in Loop

The for loop, or for/in loop, iterates through the elements of an enumerable object (such as an array). On each iteration, it assigns an element to a specified loop variable and then executes the body of the loop. A for loop looks like this:

for var in collection do
  body
end

var is a variable or a comma-separated list of variables. collection is 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. As with the while and until loops, the do keyword is optional and may be replaced with a newline or semicolon.

Here are some sample for loops:

# Print the elements in an array
array = [1,2,3,4,5]
for element in array 
  puts element
end

# Print the keys and values in a hash
hash = {:a=>1, :b=>2, :c=>3}
for key,value in hash
  puts "#{key} => #{value}"
end

The loop variable or variables of a for loop are not local to the loop; they remain defined even after the loop exits. Similarly, new variables defined within the body of the loop continue to exist after the loop exits.

The fact that the for loop depends on the each iterator method implies that for loops are much like iterators. For example, the for loop shown above for enumerating the keys and values of a hash could also be written with an explicit use of the each iterator:

hash = {:a=>1, :b=>2, :c=>3}
hash.each do |key,value|
  puts "#{key} => #{value}"
end

The only difference between the for version of the loop and the each version is that the block of code that follows an iterator does define a new variable scope. Details are in the discussion of iterators later in this chapter.



[*] In Ruby 1.8, a colon may be used in place of the do keyword. This is no longer allowed in Ruby 1.9.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.160.43