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


84

我试图通过捕获异常来提高我的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

Answers:


168

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

通常,负责处理错误的人是对象的用户:调用者。如果我们对错误感兴趣但又不想承担该责任怎么办?我们挽救错误,执行所需的任何操作,然后将信号向上传播到堆栈,就好像什么都没发生一样。

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

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

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

在您提出的示例中,根本没有必要重新引发错误。您可以简单地让它自然地在堆栈中传播。您的示例中的唯一区别是,您要创建一个新的错误对象并将其引发,而不是重新引发最后一个错误对象。


有趣。我的问题是,如果我没有捕获到流程定义中的错误,那么当我调用流程方法时就需要捕获它,例如:begin @logo.process; rescue...,但是那样我就不会捕获由流程本身启动的异常,但在流程中已被调用。那是正确的吗?
霍默·史密斯

2
这会使stacktrace原始异常失去作用,您可能想包括cause在ruby> 2.1中可用的异常
bjhaid 2014年

4
@bjhaidraise以这种答案的方式进行调用将完全保留原始异常,包括backtracecause不适用于这种情况。相反,当rescue块引发新异常时,它将自动填充。
代表

@HommerSmith:如果加注前的行(在这种情况下为log.error,但可能是任何东西)失败怎么办?我正在考虑“确保”它,但是,在确保内部,我需要将对错误的引用用作“ raise”的参数。您对此有何看法?
jgomo3

1
@RafałCieślak每次引发错误时,都会将其分配给$!全局变量。raise不带参数的调用会引发中包含的错误$!,从而有效地引发最后一个错误。但是,raise error将引发error局部变量中包含的错误,该变量可能与可能不相同$!。在我的示例中,$!与相同error。但是,也可以这样做:error = Exception.new; raise error
Matheus Moreira

3

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

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

我建议抓住StandardError是一个坏主意,因为它包含所有各种较低级别的函数,并且可能会挂起您的程序。
保罗·怀特黑德

1
我认为这是规则的“例外”,因为我们立即再次提出了例外。
FreePender
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.