在Ruby中捕获异常后重新获取(相同的异常)

Hom*_*ith 60 ruby exception

我试图通过捕获异常来提高我的Ruby技能.我想知道当你有几个方法调用时,是否通常会重新提出相同类型的异常.那么,以下代码是否有意义?是否可以重新引用相同类型的异常,或者我不应该在处理方法上捕获它?

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
Run Code Online (Sandbox Code Playgroud)

Mat*_*ira 118

有时我们只是想知道发生了错误,而不必实际处理错误.

通常情况是负责处理错误的人是对象的用户:调用者.如果我们对错误感兴趣但又不想承担这个责任怎么办?我们拯救错误,做我们需要做的任何事情,然后将信号传播到堆栈中,好像什么也没发生过一样.

例如,如果我们想记录错误消息然后让调用者处理它呢?

begin
  this_will_fail!
rescue Failure => error
  log.error error.message
  raise
end
Run Code Online (Sandbox Code Playgroud)

raise不带任何参数调用将引发最后一个错误.就我们而言,我们正在重新筹集资金error.

在您在问题中提供的示例中,根本不需要重新引发错误.你可以简单地让它自然地向上传播.您的示例中唯一的区别是您正在创建一个新的错误对象并提升它而不是重新提升最后一个.

  • @bjhaid以这个答案的方式调用`raise`会完全保留原始异常,包括`backtrace`.`cause`不适用于这种情况.相反,当`rescue`块引发新的异常时,它会自动填充. (4认同)
  • @RafałCieślak 每次出现错误时,都会将其分配给“$!”全局变量。调用不带参数的“raise”会引发“$!”中包含的错误,从而有效地引发最后一个错误。但是,“raise error”将引发“error”局部变量中包含的错误,该变量可能与“$!”中包含的对象相同,也可能不同。在我的示例中,“$!”与“error”相同。然而,也可以这样做:`error = Exception.new; 引发错误` (4认同)
  • @HommerSmith:如果 raise 之前的行(在本例中为 log.error,但它可能是任何内容)失败怎么办?我正在考虑“确保”它,但是,在确保内部我需要使用对错误的引用作为“raise”的参数。你对此有何看法? (3认同)
  • 这会从原始异常中松散`stacktrace`,你可能想要包含在ruby> 2.1中可用的异常`cause` (2认同)
  • @RafałCieślak,这并不像“每次出现错误时,它都会被分配给 $!”那么简单。全局变量`; 我在[此处]发布了完整的解释(/sf/answers/4875704711/) (2认同)

Fre*_*der 5

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

rescue StandardError => e
  raise e.class, "Message: #{e.message}"
Run Code Online (Sandbox Code Playgroud)

  • 我知道已经过去一年了,但是捕获 StandardError 是安全的,@PaulWhitehead ——这是你绝对不能捕获的 Exception。(快速来源:https://thoughtbot.com/blog/rescue-standarderror-not-exception) (4认同)
  • 我相信这是规则的“例外”,因为我们立即再次提出例外。 (3认同)

use*_*679 5

我和这里的评论线程有同样的问题,即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
Run Code Online (Sandbox Code Playgroud)

上面的输出是:

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

此行为与 Python 的工作方式不同(re)raise

状态的文档Exception

当异常已引发但尚未处理时(在rescueensure和块中),将设置两个全局变量at_exitEND

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

因此,这些变量不是真正的全局变量,它们仅在处理错误的块内定义。

begin
  raise
rescue
  p $!  # StandardError
end

p $!    # nil
Run Code Online (Sandbox Code Playgroud)