在Ruby中捕获异常后重新引发(相同异常)

pkbketx9  于 2022-11-04  发布在  Ruby
关注(0)|答案(5)|浏览(216)

我正在尝试通过捕捉异常来提高我的Ruby技能。我想知道,当你有几个方法调用时,是否经常重新引发同一类异常。那么,下面的代码是否有意义?重新引发同一类异常是否可以,或者我是否应该在process方法上捕捉它?

class Logo
  def process
    begin
      @processed_logo = LogoProcessor::create_image(self.src)
    rescue CustomException
      raise CustomException
    end
  end
end

module LogoProcessor
  def self.create_image
    raise CustomException if some_condition
  end
end
ryoqjall

ryoqjall1#

有时我们只想知道错误 * 发生了 *,而不必实际 * 处理 * 错误。
通常情况下,负责处理错误的人是对象的用户:如果我们对错误感兴趣,但不想承担责任,该怎么办?我们挽救错误,做我们需要做的任何事情,然后将信号向上传播到堆栈,就像什么都没有发生一样。
例如,如果我们想记录错误消息,然后让调用者处理它,该怎么办?

begin
  this_will_fail!
rescue Failure => error
  log.error error.message
  raise
end

不带任何参数调用raise将引发最后一个错误。在本例中,我们将重新引发error
在你的问题中所展示的例子中,重新引发错误是完全没有必要的。你可以让它自然地向上传播堆栈。你的例子中唯一的区别是你创建了一个新的错误对象并引发它,而不是重新引发最后一个。

qv7cva1a

qv7cva1a2#

这将引发与原始错误类型相同的错误,但您可以自定义消息。

rescue StandardError => e
  raise e.class, "Message: #{e.message}"
dluptydi

dluptydi3#

我有同样的问题在这里的评论线程,即What if the line before (re)raise fails?
我的理解受到了$!的全局变量是“有点垃圾收集的”//“作用域到它的函数上下文”这一缺失知识的限制,下面的示例演示了这一点:

def func
  begin
    raise StandardError, 'func!'
  rescue StandardError => err
    puts "$! = #{$!.inspect}"
  end
end

begin
  raise StandardError, 'oh no!'
rescue StandardError => err
  func
  puts "$! = #{$!.inspect}"
  raise
end

上面的输出是:

$! = #<StandardError: func!>
$! = #<StandardError: oh no!>
StandardError: oh no!
from (pry):47:in `__pry__'

这种行为与Python的(re)raise的工作方式不同。
The documentation for Exception声明:
当已引发异常但尚未处理时(在rescueensureat_exitEND块中),将设置两个全局变量:

  • $!包含当前异常。
  • $@包含其回溯。

所以这些变量不是真正的全局变量,它们只在处理错误的块中定义。

begin
  raise
rescue
  p $!  # StandardError
end

p $!    # nil
nbewdwxp

nbewdwxp4#

做同样的事情as FreePender的一个稍微好一点的方法是使用Exception类中的exception方法,Exception类是任何错误类(如StandardError)的祖先类,因此该方法可用于任何错误类。
以下是ApiDock上的方法文档:
不带参数,或者如果参数与接收方相同,则返回接收方。否则,创建一个与接收方相同类的新异常对象,但消息等于string.to_str。
现在让我们来看看它是如何工作的:

begin
  this_will_fail!
rescue Failure => error
  raise error.exception("Message: #{error.message}")
end
a14dhokn

a14dhokn5#

在此补充上述答案:

  • 在某些应用程序中,您可能需要记录错误两次。
  • 例如,需要将异常通知给Nagios/Newrelate/Cloudwatch等监控工具。
  • 同时,您可能有自己的kibana支持的摘要日志记录工具,供内部参考。

在这些情况下,您可能需要多次记录和处理错误。

范例:

begin
  begin
    nil.to_sym
  rescue => e
    puts "inner block error message: #{e.message}"
    puts "inner block backtrace: #{e.backtrace.join("\n")}"
    raise e
  end
rescue => e
  puts "outer block error message: #{e.message}"
  puts "outer block backtrace: #{e.backtrace.join("\n")}"
end

我在这里使用了put,为了方便您在Rails控制台中验证此代码,在实际生产中,您可能需要使用Rails logger

相关问题