在捕获和重新引发 Ruby 异常时,如何防止出现两个异常堆栈?

How do I prevent two exception stacks when catching and re-raising Ruby exceptions?

提问人:pedz 提问时间:8/29/2022 更新时间:8/29/2022 访问量:55

问:

在一个更大的项目中,我正在捕获特定的异常,在消息中添加一些详细信息,然后重新引发相同的异常。这是我正在做的事情的基本想法。

#!/usr/bin/env ruby

begin
  puts 12 / 0
rescue ZeroDivisionError => e
  raise e.exception("new message #{e.message}")
end

当我从命令行执行temp.rb时,会打印两个异常:

 % ./temp.rb
./temp.rb:4:in `/': new message divided by 0 (ZeroDivisionError)
    from ./temp.rb:4:in `<main>'
./temp.rb:4:in `/': divided by 0 (ZeroDivisionError)
    from ./temp.rb:4:in `<main>'

我假设某处有一个异常堆栈或异常列表,并且 Ruby 的退出过程会打印出整个异常列表或堆栈。我可以看到这样做的好处。但就我而言,我想从列表或堆栈中删除原始异常。有没有办法做到这一点?

Ruby 异常

评论

0赞 Konstantin Strukov 8/29/2022
你在寻找这个 ruby-doc.org/core-3.1.2/Exception.html#method-i-set_backtrace 吗?

答:

2赞 Holger Just 8/29/2022 #1

“第二个”(原始)异常是获救异常的原因,该异常在创建新异常时被引用。Exception#exception

从 Ruby 3.1 开始,除了实际异常之外,还会打印原因的详细信息,以帮助调试。以前的 Ruby 版本忽略了 here。irbcause

因此,您可以使用其他方式来处理异常,而不是使用 Ruby 的默认处理程序来打印其他未处理的异常的详细信息,例如通过添加显式异常处理程序。或者,您也可以在创建新异常时显式设置:cause

begin
  puts 12 / 0
rescue ZeroDivisionError => e
  raise e.class, "new message #{e.message}", cause: nil
end
0赞 mechnicov 8/29/2022 #2

可能是这样的东西,可以使用自定义方法进行扩展Exception

Exception.class_eval do
  def add_message(msg)
    mod =
      Module.new do
        define_method :to_s do
          "#{super()} #{msg}"
        end
      end

    extend mod
  end
end

然后

begin
  puts 12 / 0
rescue ZeroDivisionError => e
  raise e.add_message("(even don't try it)")
end