Document throw/catch in the control expressions document [ci skip]
This are implemented as Kernel methods and not keywords, but I still think they are worth documenting with the other control flow expressions.
This commit is contained in:
parent
4847b7ac28
commit
618a04d211
Notes:
git
2023-05-26 14:59:06 +00:00
Merged: https://github.com/ruby/ruby/pull/7856 Merged-By: jeremyevans <code@jeremyevans.net>
@ -569,3 +569,71 @@ evaluated on the following iteration:
|
|||||||
Here, the flip-flop turns on when +value+ equals 2, but doesn't turn off on the
|
Here, the flip-flop turns on when +value+ equals 2, but doesn't turn off on the
|
||||||
same iteration. The `off' condition isn't evaluated until the following
|
same iteration. The `off' condition isn't evaluated until the following
|
||||||
iteration and +value+ will never be two again.
|
iteration and +value+ will never be two again.
|
||||||
|
|
||||||
|
== throw/catch
|
||||||
|
|
||||||
|
+throw+ and +catch+ are used to implement non-local control flow in Ruby. They
|
||||||
|
operate similarly to exceptions, allowing control to pass directly from the
|
||||||
|
place where +throw+ is called to the place where the matching +catch+ is
|
||||||
|
called. The main difference between +throw+/+catch+ and the use of exceptions
|
||||||
|
is that +throw+/+catch+ are designed for expected non-local control flow,
|
||||||
|
while exceptions are designed for exceptional control flow situations, such
|
||||||
|
as handling unexpected errors.
|
||||||
|
|
||||||
|
When using +throw+, you provide 1-2 arguments. The first argument is the
|
||||||
|
value for the matching +catch+. The second argument is optional (defaults to
|
||||||
|
+nil+), and will be the value that +catch+ returns if there is a matching
|
||||||
|
+throw+ inside the +catch+ block. If no matching +throw+ method is called
|
||||||
|
inside a +catch+ block, the +catch+ method returns the return value of the
|
||||||
|
block passed to it.
|
||||||
|
|
||||||
|
def a(n)
|
||||||
|
throw :d, :a if n == 0
|
||||||
|
b(n)
|
||||||
|
end
|
||||||
|
|
||||||
|
def b(n)
|
||||||
|
throw :d, :b if n == 1
|
||||||
|
c(n)
|
||||||
|
end
|
||||||
|
|
||||||
|
def c(n)
|
||||||
|
throw :d if n == 2
|
||||||
|
end
|
||||||
|
|
||||||
|
4.times.map do |i|
|
||||||
|
catch(:d) do
|
||||||
|
a(i)
|
||||||
|
:default
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# => [:a, :b, nil, :default]
|
||||||
|
|
||||||
|
If the first argument you pass to +throw+ is not handled by a matching
|
||||||
|
+catch+, an UncaughtThrowError exception will be raised. This is because
|
||||||
|
+throw+/+catch+ should only be used for expected control flow changes, so
|
||||||
|
using a value that is not already expected is an error.
|
||||||
|
|
||||||
|
+throw+/+catch+ are implemented as Kernel methods (Kernel#throw and
|
||||||
|
Kernel#catch), not as keywords. So they are not usable directly if you are
|
||||||
|
in a BasicObject context. You can use Kernel.throw and Kernel.catch in
|
||||||
|
this case:
|
||||||
|
|
||||||
|
BasicObject.new.instance_exec do
|
||||||
|
def a
|
||||||
|
b
|
||||||
|
end
|
||||||
|
|
||||||
|
def b
|
||||||
|
c
|
||||||
|
end
|
||||||
|
|
||||||
|
def c
|
||||||
|
::Kernel.throw :d, :e
|
||||||
|
end
|
||||||
|
|
||||||
|
result = ::Kernel.catch(:d) do
|
||||||
|
a
|
||||||
|
end
|
||||||
|
result # => :e
|
||||||
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user