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.
加载中,请稍侯......
精彩评论