Exception clears the stack trace of what?
I am reading this blog and came across following code
RunAgain = Class.new(Exception)
def fib(i, n = 1, result = 0)
if i == -1
result
else
raise RunAgain
end
rescue RunAgain
i, n, result = i - 1, n + result, n
r开发者_如何学编程etry
end
It seems like for above code to work, once exception is raised then ruby must be clearing the whole stack trace and replacing that with the stack of Exception.
Is my understanding right?
The way this code works actually has nothing to do with the stacktrace. There are two entries on the stack the entire time, fib
and the caller of fib
. The raise of the exception is sort of a red herring to your question--it doesn't serve any useful purpose in this example other than as a demonstration of the behavior of retry
.
Ruby's retry
is similar to other control keywords like next
and break
, and redo
. The redo
keyword means to retry the current loop or block from the top. The retry
keyword works inside a rescue to retry the current block that threw the exception.
So what happens here is some initial values are set for i
, n
, and result
, a base case is checked (i == -1
), and if not satisfied, we update the values and retry from the top. Notice that since these values are method parameters and not local variables, they are not reinitialized.
Careful, since Fibonacci is a very common example (and a very poor one) of recursion, not to mistake this for a recursive algorithm. The RunAgain
raise and rescue functions like a loop, without re-calling the function or modifying the callstack.
Your example code is equivalent to
def fib(i)
n, result = 1, 0
(i+1).times { n, result = n + result, n }
result
end
Note in both cases, i
is just a counter and nothing more. We run the code i+1
times. Note also the typical need for a temporary variable to swap values is replaced by ruby's multiple assignment construct.
精彩评论