如何使用 raise 和 rescue 块在 Ruby 中实现错误处理

418 阅读5分钟

异常处理指的是预测和定义处理程序执行过程中出现的错误的方法。在大多数情况下,错误是指在程序执行过程中出现的意外事件或发生的情况。例如,在读取文件时可能会发生错误,原因是文件不存在或用户没有读取或写入文件的正确权限。

本教程将向你展示如何在Ruby中使用提高和救援块来实现异常处理。

基本用法

大多数编程语言使用try和catch块来实现异常处理。然而,就像Ruby中的其他东西一样,关键字的描述性更强。

我们可以把一般的语法表达出来,如下所示。

begin
raiseexception
        # raise ecxeption
    rescue exception
        # rescue block
end

我们用begin和end语句来包围异常处理块。在这些语句中,我们定义了 raise 和 rescue 块。

在 raise 中,我们定义了异常,我们可以手动提出,也可以让 Ruby 解释器生成。默认情况下,提高块的参数是 RuntimeError

接下来是救援块。顾名思义,当异常发生时,这个块会来救援。它负责控制程序的执行。

Ruby 将比较从 raise 块引发的异常和传递给救援块的参数。如果异常的类型相同或属于超类,它将触发救援块。

Ruby中异常处理的例子

我们可以实现一个简单的例子来说明Ruby中的异常处理是如何工作的。

def err_me

begin

puts "Hi there!"

raise "string type"

rescue

puts "Never mind, I am fixed!"

end
end
err_me

在上面的例子中,我们定义了一个带有异常块的函数。

我们手动引发了一个异常,中断了程序的执行流程并进入救援块。这样就执行了块中的动作--在本例中是一个put语句并退出。

如果你在 raise 之后和救援块之前添加任何代码块,它们都不会执行,因为救援块会立即处理程序流。

默认情况下,救援块使用 StandardError 参数。然而,在Ruby中还有其他类型的错误,包括。

  1. 语法错误(SyntaxError
  2. IOError
  3. RegexpError
  4. 线程错误
  5. 零除法错误
  6. 没有方法的错误
  7. 索引错误
  8. 名称错误
  9. 类型错误

还有更多。

为了提高和处理一个特定的错误类型,我们可以把它作为一个参数传递给提高块。下面是一个例子。

begin
raiseZeroDivisionError
rescue =>exception
    puts exception.message
    puts exception.backtrace.inspect
end

在上面的例子中,我们提出了一个ZeroDivisionError。然后我们跳转到救援块,它打印出特定的异常类型并追踪其来源。

结果输出为

$ ruby err-handling.rb
ZeroDivisionError
["err-handling.rb:2:in `<main>'"]

其他异常块

除了主要的 raise 和 rescue 块,Ruby 还为我们提供了其他可以实现的块来处理错误。

它们包括。

重试块

重试块是用来在引发异常后重新运行救援块的。下面是一个例子。

begin
    raise ZeroDivisionError
    puts "I don't run 😢"
rescue => exception
    puts "#{exception.message} caused me to die ⚰️"
retry
end

如果我们运行上面的代码,它将打印救援块内的信息。它将遇到重试块,重试块会跳到救援块中。

重试块的一个常见用例是使用蛮力探测错误。一个例子是在连接中断时不断重载一个页面,直到错误解决。

注意: 使用重试块时要小心,因为它是无限循环的一个常见来源。

确保块

如果你用其他语言(如Python)编程,你可能对Final块很熟悉。Ruby中的确保块与其他编程语言中的最后块的性能相似。

ensure块总是在代码的最后运行。无论提出的异常是否被正确处理或程序执行是否终止,它总是运行或执行。

下面是一个例子。

begin
    raise ZeroDivisionError
    puts "I don't run 😢"
rescue => exception
    puts "#{exception.message} caused me to die ⚰️"
ensure
    puts "I will always run 🚀"
end

在这种情况下,上面的代码将打印一个异常消息,最后运行确保块。

ZeroDivisionError caused me to die ⚰️

I will always run 🚀

Else块

如果没有产生异常,我们可以使用else语句实现一个块来做一个动作。

比如说

begin
rescue => exception
    puts "#{exception.message} caused me to die ⚰️"
else
    puts "Trust me, I ran successfully 😀"
ensure
    puts "& I will always run 🚀"
end

else块被放在救援和确保块之间。在上面的例子中,你会注意到它缺少一个 raise 块,它导致 else 块的运行。

下面是一个输出示例。

相信,我运行成功了😀

& I will always run 🚀

轻量级异常处理

raise和save块是一种方便的方法,当错误发生时可以执行一个动作。然而,由于错误处理会建立一个堆栈跟踪来帮助调试,它很容易在你的程序中成为问题。这就是catch和throw块的用处。

要实现catch-throw块,你首先要用catch关键字定义标签。一旦ruby遇到引用catch块的throw块,它就会停止执行并跳转到catch块。

让我们用一个例子来说明这个概念。考虑一下下面代码中所示的混乱嵌套。

catch(:kill_me_now) do
langs = ["Python", "Ruby", "C++", "C#"]
foriinlangsdo
for index in 1..5
if index == 3
ifi == "C#"
                puts "After throw, nothing will run!'"
                throw(:kill_me_now)
                puts "I am C#"
end
end
end
end
end
puts "Oh boy! That was a long one!"

我们首先使用catch关键字,并在一对括号内传递标签。一旦我们运行代码,它将执行所有的嵌套循环和if语句,直到它遇到引用catch的throw语句。

这将立即终止执行并退出到catch语句的层次。

下面是一个输出的例子。

After throw, nothing will run!'
Oh boy! That was a long one!

总结

本教程向你展示了如何使用 raise 和 rescue 块在 Ruby 中实现错误处理。