mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* doc/syntax/control_expressions.rdoc: Added description of control
expressions in ruby. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38827 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
68b072bfba
commit
e071e13068
2 changed files with 404 additions and 0 deletions
|
@ -1,3 +1,8 @@
|
|||
Tue Jan 15 15:55:28 2013 Eric Hodel <drbrain@segment7.net>
|
||||
|
||||
* doc/syntax/control_expressions.rdoc: Added description of control
|
||||
expressions in ruby.
|
||||
|
||||
Tue Jan 15 13:33:00 2013 Eric Hodel <drbrain@segment7.net>
|
||||
|
||||
* doc/syntax/methods.rdoc (Method Names): Added method names including
|
||||
|
|
399
doc/syntax/control_expressions.rdoc
Normal file
399
doc/syntax/control_expressions.rdoc
Normal file
|
@ -0,0 +1,399 @@
|
|||
= Control Expressions
|
||||
|
||||
Ruby has a variety of ways to control execution. All the expressions described
|
||||
here return a value.
|
||||
|
||||
For the tests in these control expressions, +nil+ and +false+ are false-values
|
||||
and +true+ and any other object are true-values. In this document "true" will
|
||||
mean "true-value" and "false" will mean "false-value".
|
||||
|
||||
== +if+ Expression
|
||||
|
||||
The simplest +if+ expression has two parts, a "test" expression and a "then"
|
||||
expression. If the "test" expression evaluates to a true then the "then"
|
||||
expression is evaluated.
|
||||
|
||||
Here is a simple if statement:
|
||||
|
||||
if true then
|
||||
puts "the test resulted in a true-value"
|
||||
end
|
||||
|
||||
This will print "the test resulted in a true-value".
|
||||
|
||||
The +then+ is optional:
|
||||
|
||||
if true
|
||||
puts "the test resulted in a true-value"
|
||||
end
|
||||
|
||||
This document will include the optional +then+ for all expressions. Many
|
||||
people omit the +then+ part of the if and other expressions.
|
||||
|
||||
You may also add an +else+ expression. If the test does not evaluate to true
|
||||
the +else+ expression will be executed:
|
||||
|
||||
if false then
|
||||
puts "the test resulted in a true-value"
|
||||
else
|
||||
puts "the test resulted in a false-value"
|
||||
end
|
||||
|
||||
This will print "the test resulted in a false-value".
|
||||
|
||||
You may add an arbitrary number of extra tests to an if expression using
|
||||
+elsif+. An +elsif+ executes when all tests above the +elsif+ are false.
|
||||
|
||||
a = 1
|
||||
|
||||
if a == 0 then
|
||||
puts "a is zero"
|
||||
elsif a == 1 then
|
||||
puts "a is one"
|
||||
else
|
||||
puts "a is some other value"
|
||||
end
|
||||
|
||||
This will print "a is one" as <code>1<code> is not equal to <code>0</code>.
|
||||
Since +else+ is only executed when there are no matching conditions.
|
||||
|
||||
Once a condition matches, either the +if+ condition or any +elsif+ condition,
|
||||
the +if+ expression is complete and no further tests will be performed.
|
||||
|
||||
In this example only "a is one" is printed:
|
||||
|
||||
a = 1
|
||||
|
||||
if a == 0 then
|
||||
puts "a is zero"
|
||||
elsif a == 1 then
|
||||
puts "a is one"
|
||||
elsif a >= 1 then
|
||||
puts "a is greater than or equal to one"
|
||||
else
|
||||
puts "a is some other value"
|
||||
end
|
||||
|
||||
The tests for +if+ and +elsif+ may have side-effects. The most common use of
|
||||
side-effect is to cache a value into a local variable:
|
||||
|
||||
if a = object.some_value then
|
||||
# do something to a
|
||||
end
|
||||
|
||||
The result value of an +if+ expression is the last value executed in the
|
||||
expression.
|
||||
|
||||
== +unless+ Expression
|
||||
|
||||
The +unless+ expression is the opposite of the +if+ expression. If the value
|
||||
is false the "then" expression is executed:
|
||||
|
||||
unless true then
|
||||
puts "the value is a false-value"
|
||||
end
|
||||
|
||||
This prints nothing as true is not a false-value.
|
||||
|
||||
Note that the above +unless+ expression is the same as:
|
||||
|
||||
if not true then
|
||||
puts "the value is a false-value"
|
||||
end
|
||||
|
||||
Like an +if+ expression you may use an +else+ condition with +unless+:
|
||||
|
||||
unless true then
|
||||
puts "the value is false"
|
||||
else
|
||||
puts "the value is true"
|
||||
end
|
||||
|
||||
This prints "the value is true" from the +else+ condition.
|
||||
|
||||
You may not use +elsif+ with an +unless+ expression.
|
||||
|
||||
The result value of an +unless+ expression is the last value executed in the
|
||||
expression.
|
||||
|
||||
== Modifier +if+ and +unless+
|
||||
|
||||
+if+ and +unless+ can also be used to modify an expression. When used as a
|
||||
modifier the left-hand side is the "then" expression and the right-hand side
|
||||
is the "test" expression:
|
||||
|
||||
a = 0
|
||||
|
||||
a += 1 if a.zero?
|
||||
|
||||
p a
|
||||
|
||||
This will print 1.
|
||||
|
||||
a = 0
|
||||
|
||||
a += 1 unless a.zero?
|
||||
|
||||
p a
|
||||
|
||||
This will print 0.
|
||||
|
||||
While the modifier and standard versions have both a "test" expression and a
|
||||
"then" expression, they are not exact transformations of each other due to
|
||||
parse order. Here is an example that shows the difference:
|
||||
|
||||
p a if a = 0.zero?
|
||||
|
||||
This raises the NameError "undefined local variable or method `a'".
|
||||
|
||||
When ruby parses this it first encounters +a+ as a method call in the "then"
|
||||
expression, then later sees +a+ as a local variable in the "test" expression.
|
||||
|
||||
When running this line it first executes the "test" expression, <code>a =
|
||||
0.zero?</code>.
|
||||
|
||||
Since the test is true it then executes the "then" expression, <code>p
|
||||
a</code>. Since the +a+ in the body was recorded as a method which does not
|
||||
exist the NameError is raised.
|
||||
|
||||
The same as true for +unless+.
|
||||
|
||||
== +case+ Expression
|
||||
|
||||
The +case+ expression can be used in two ways.
|
||||
|
||||
The most common way is to compare an object against multiple patterns. The
|
||||
patterns are matched using the +===+ method which is aliased to +==+ on
|
||||
Object. Other classes must override it to give meaningful behavior. See
|
||||
Module#=== and Regexp#=== for examples.
|
||||
|
||||
Here is an example of using +case+ to compare a String against a pattern:
|
||||
|
||||
case "12345"
|
||||
when /^1/ then
|
||||
puts "the string starts with one"
|
||||
else
|
||||
puts "I don't know what the string starts with"
|
||||
end
|
||||
|
||||
Here the string <code>"12345"</code> is compared with <code>/^1/</code> by
|
||||
calling <code>/^1/ === "12345"</code> which returns +true+. Like the +if+
|
||||
expression the first +when+ that matches is executed and all other matches are
|
||||
ignored.
|
||||
|
||||
If no matches are found the +else+ is executed.
|
||||
|
||||
The +else+ and +then+ are optional, this +case+ expression gives the same
|
||||
result as the one above:
|
||||
|
||||
case "12345"
|
||||
when /^1/
|
||||
puts "the string starts with one"
|
||||
end
|
||||
|
||||
You may place multiple conditions on the same +when+:
|
||||
|
||||
case "2"
|
||||
when /^1/, "2" then
|
||||
puts "the string starts with one or is '2'"
|
||||
end
|
||||
|
||||
Ruby will try each condition in turn, so first <code>/^1/ === "2"</code>
|
||||
returns +false+, then <code>"2" === "2"</code> returns +true+, so "the string
|
||||
starts with one or is '2'" is printed.
|
||||
|
||||
The other way to use a +case+ expression is like an if-elsif expression:
|
||||
|
||||
a = 2
|
||||
|
||||
case
|
||||
when a == 1, a == 2 then
|
||||
puts "a is one or two"
|
||||
when a == 3 then
|
||||
puts "a is three"
|
||||
else
|
||||
puts "I don't know what a is"
|
||||
end
|
||||
|
||||
Again, the +then+ and +else+ are optional.
|
||||
|
||||
The result value of a +case+ expression is the last value executed in the
|
||||
expression.
|
||||
|
||||
== +while+ Loop
|
||||
|
||||
The +while+ loop executes while a condition is true:
|
||||
|
||||
a = 0
|
||||
|
||||
while a < 10 do
|
||||
p a
|
||||
a += 1
|
||||
end
|
||||
|
||||
p a
|
||||
|
||||
Prints the numbers 0 through 10. The condition <code>a < 10</code> is checked
|
||||
before the loop is entered, then the body executes, then the condition is
|
||||
checked again. When the condition results in false the loop is terminated.
|
||||
|
||||
The +do+ keyword is optional. The following loop is equivalent to the loop
|
||||
above:
|
||||
|
||||
while a < 10
|
||||
p a
|
||||
a += 1
|
||||
end
|
||||
|
||||
The result of a +while+ loop is +nil+ unless +break+ is used to supply a
|
||||
value.
|
||||
|
||||
== +until+ Loop
|
||||
|
||||
The +until+ loop executes while a condition is false:
|
||||
|
||||
a = 0
|
||||
|
||||
until a > 10 do
|
||||
p a
|
||||
a += 1
|
||||
end
|
||||
|
||||
p a
|
||||
|
||||
This prints the numbers 0 through 11. Like a while loop the condition <code>a
|
||||
> 10</code> is checked when entering the loop and each time the loop body
|
||||
executes. If the condition is false the loop will continue to execute.
|
||||
|
||||
Like a +while+ loop the +do+ is optional.
|
||||
|
||||
Like a +while+ loop the result of an +until+ loop is nil unless +break+ is
|
||||
used.
|
||||
|
||||
== +for+ Loop
|
||||
|
||||
The +for+ loop consists of +for+ followed by a variable to contain the
|
||||
iteration argument followed by +in+ and the value to iterate over using #each.
|
||||
The +do+ is optional:
|
||||
|
||||
for value in [1, 2, 3] do
|
||||
puts value
|
||||
end
|
||||
|
||||
Prints 1, 2 and 3.
|
||||
|
||||
The +for+ loop is similar to using #each, but does not create a new variable
|
||||
scope.
|
||||
|
||||
The result value of a +for+ loop is the value iterated over unless +break+ is
|
||||
used.
|
||||
|
||||
The +for+ loop is rarely used in modern ruby programs.
|
||||
|
||||
== Modifier +while+ and +until+
|
||||
|
||||
Like +if+ and +unless+, +while+ and +until+ can be used as modifiers:
|
||||
|
||||
a = 0
|
||||
|
||||
a += 1 while a < 10
|
||||
|
||||
p a # prints 10
|
||||
|
||||
+until+ used as a modifier:
|
||||
|
||||
a = 0
|
||||
|
||||
a += 1 until a > 10
|
||||
|
||||
p a # prints 11
|
||||
|
||||
You can use +begin+ and +end+ to create a +while+ loop that runs the body once
|
||||
before the condition:
|
||||
|
||||
a = 0
|
||||
|
||||
begin
|
||||
a += 1
|
||||
end while a < 10
|
||||
|
||||
p a # prints 10
|
||||
|
||||
If you don't use +rescue+ or +ensure+ Ruby optimizes away any exception
|
||||
handling overhead.
|
||||
|
||||
== +break+ Statement
|
||||
|
||||
Use +break+ to leave a block early. This will stop iterating over the items in +values+ if one of them is even:
|
||||
|
||||
values.each do |value|
|
||||
break if value.even?
|
||||
|
||||
# ...
|
||||
end
|
||||
|
||||
You can also terminate from a +while+ loop using +break+:
|
||||
|
||||
a = 0
|
||||
|
||||
while true do
|
||||
p a
|
||||
a += 1
|
||||
|
||||
break if a < 10
|
||||
end
|
||||
|
||||
p a
|
||||
|
||||
This prints the numbers 0 and 1.
|
||||
|
||||
+break+ accepts a value that supplies the result of the expression it is
|
||||
"breaking" out of:
|
||||
|
||||
result = [1, 2, 3].each do |value|
|
||||
break value * 2 if value.even?
|
||||
end
|
||||
|
||||
p result # prints 4
|
||||
|
||||
== +next+ Statement
|
||||
|
||||
Use +next+ to skip the rest of the current iteration:
|
||||
|
||||
result = [1, 2, 3].map do |value|
|
||||
next if value.even?
|
||||
|
||||
value * 2
|
||||
end
|
||||
|
||||
p result # prints [2, nil, 6]
|
||||
|
||||
+next+ accepts an argument that can be used the result of the current block
|
||||
iteration:
|
||||
|
||||
result = [1, 2, 3].map do |value|
|
||||
next value if value.even?
|
||||
|
||||
value * 2
|
||||
end
|
||||
|
||||
p result # prints [2, 2, 6]
|
||||
|
||||
== +redo+ Statement
|
||||
|
||||
Use +redo+ to redo the current iteration:
|
||||
|
||||
result = []
|
||||
|
||||
while result.length < 10 do
|
||||
result << result.length
|
||||
|
||||
redo if result.last.even?
|
||||
|
||||
result << result.length + 1
|
||||
end
|
||||
|
||||
p result
|
||||
|
||||
This prints [0, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11]
|
||||
|
Loading…
Add table
Reference in a new issue