使用
fail方法来抛出异常。仅在捕捉到异常时使用raise来重新抛出异常(因为没有失败,所以只是显式地有目的性地抛出一个异常)begin fail "Oops"; rescue => error raise if error.message != "Oops" end如果
fail/raise只有两个参数,无需显性指定RuntimeError。# 差 fail RuntimeError, "message" # 好——默认就是 RuntimeError fail "message"将异常类和消息作为参数给
fail/raise,而不是异常类的的实例。# 差 fail SomeException.new("message") # 无法使用 `fail SomeException.new("message"), backtrace`. # 好 fail SomeException, "message" # 可以使用 `fail SomeException, "message", backtrace`.永远不要从
ensure区块返回。如果你显式地从ensure区块中的一个方法返回,那么这方法会如同没有异常般的返回。实际上,异常会被默默丢掉。def foo begin fail ensure return "very bad idea" end end尽可能使用隐式的
begin区块。# 差 def foo begin # 此处放主要逻辑 rescue # 错误处理放在此处 end end # 好 def foo # 此处放主要逻辑 rescue # 错误处理放在此处 end通过 contingency 方法 (一个由 Avdi Grimm 创造的词) 来减少
begin区块的使用。# 差 begin something_that_might_fail rescue IOError # 处理 IOError end begin something_else_that_might_fail rescue IOError # 处理 IOError end # 好 def with_io_error_handling yield rescue IOError # 处理 IOError end with_io_error_handling { something_that_might_fail } with_io_error_handling { something_else_that_might_fail }不要抑制异常。
begin # 这里发生了一个异常 rescue SomeError # 拯救子句完全没有做事 end # 差 do_something rescue nil避免使用
rescue的修饰符形式。# 差 - 这捕捉了所有的 StandardError 异常。 do_something rescue nil不要为了控制流程而使用异常。
# 差 begin n / d rescue ZeroDivisionError puts "Cannot divide by 0!" end # 好 if d.zero? puts "Cannot divide by 0!" else n / d end避免救援
Exception类别。这会把信号困住,并呼叫exit,导致你需要kill -9进程。# 差 begin # 呼叫 exit 及杀掉信号会被捕捉(除了 kill -9) exit rescue Exception puts "you didn"t really want to exit, right?" # 异常处理 end # 好 begin # 一个不明确的 rescue 子句捕捉的是 StandardError, # 而不是许多编程者所设想的 Exception。 rescue => e # 异常处理 end # 也好 begin # 这里发生一个异常 rescue StandardError => e # 异常处理 end把较具体的异常放在救援串连的较上层,不然它们永远不会被拯救。
# 差 begin # 一些代码 rescue Exception => e # 一些处理 rescue StandardError => e # 一些处理 end # 好 begin # 一些代码 rescue StandardError => e # 一些处理 rescue Exception => e # 一些处理 end在
ensure区块中释放你的程式的外部资源。f = File.open("testfile") begin # .. 处理 rescue # .. 错误处理 ensure f.close unless f.nil? end倾向使用标准库的异常类而不是导入新的异常类。