异常清除堆栈跟踪的内容是什么?

时间:2010-12-06 22:35:22

标签: ruby

我正在阅读this blog并遇到以下代码

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
  retry
end

似乎上面的代码工作,一旦异常被引发,那么ruby必须清除整个堆栈跟踪并用异常堆栈替换它。

我的理解是对的吗?

1 个答案:

答案 0 :(得分:2)

此代码的工作方式实际上与堆栈跟踪无关。整个时间堆栈上有两个条目fibfib的调用者。异常的提升对你的问题来说是一种红色的鲱鱼 - 除了作为retry行为的证明之外,它在这个例子中没有任何用处。

Ruby的retry与其他控制关键字类似,例如nextbreak以及redoredo关键字表示从顶部重试当前循环或块。 retry关键字在救援内部起作用,以重试引发异常的当前阻止。

所以这里发生的是为inresult设置了一些初始值,检查了基本情况(i == -1),如果不满意,我们更新值并从顶部重试。请注意,由于这些值是方法参数而不是局部变量,因此不会重新初始化它们。

小心,因为Fibonacci是递归的一个非常常见的例子(并且是非常差的一个),而不是将其误认为是递归算法。 RunAgain引发和救援功能就像一个循环,无需重新调用函数或修改callstack。

您的示例代码等同于

def fib(i)
  n, result = 1, 0
  (i+1).times { n, result = n + result, n }
  result
end

请注意,在这两种情况下,i只是一个计数器,仅此而已。我们运行代码i+1次。另请注意,交换值的临时变量的典型需求由ruby的多重赋值构造替换。