ZetCode

Ruby ensure 关键字

最后修改日期:2025 年 4 月 27 日

本教程解释了如何使用 Ruby 的 ensure 关键字。ensure 子句保证代码的执行,无论是否发生异常。

ensure 关键字定义了一个块,该块总是在 begin 块之后执行,无论是否发生异常。它通常用于清理操作。

ensurebeginrescueelse 关键字一起工作。它在正常执行或任何 rescue 块之后运行。即使您提前返回或引发另一个异常,代码也会执行。

基本的 ensure 示例

这个简单的示例演示了 ensure 的基本用法。无论是否发生异常,ensure 块都会运行。

basic_ensure.rb
begin
  puts "Performing operation"
  raise "Error occurred" if rand < 0.5
rescue => e
  puts "Rescued: #{e.message}"
ensure
  puts "This always runs"
end

ensure 块会在操作成功或失败时执行。这使其成为关闭文件或释放资源的清理任务的理想选择。

使用 ensure 进行文件处理

ensure 的一个常见用途是确保文件被正确关闭。本示例显示了即使发生异常,也进行了适当的文件处理。

file_handling.rb
begin
  file = File.open("data.txt", "w")
  file.puts "Writing important data"
  raise "Disk error" if rand < 0.3
rescue => e
  puts "Error writing file: #{e}"
ensure
  if file
    file.close
    puts "File closed successfully"
  end
end

文件保证会关闭,防止资源泄露。if file 检查确保我们不会尝试关闭一个从未打开的文件。

使用 ensure 进行数据库连接

数据库连接应始终正确关闭。本示例显示了 ensure 如何保证连接的清理。

database.rb
require 'sqlite3'

begin
  db = SQLite3::Database.new("test.db")
  db.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")
  db.execute("INSERT INTO users (name) VALUES ('John')")
rescue SQLite3::Exception => e
  puts "Database error: #{e}"
ensure
  if db
    db.close
    puts "Database connection closed"
  end
end

无论操作成功还是失败,数据库连接都会关闭。这可以防止可能耗尽数据库资源的连接泄露。

带 return 语句的 ensure

即使在方法中使用 returnensure 块也会运行。本示例演示了这种行为。

return_ensure.rb
def test_ensure
  begin
    puts "Starting method"
    return "Early return" if rand < 0.5
    puts "Normal execution"
  ensure
    puts "Ensure block executed"
  end
end

puts test_ensure

ensure 块在方法返回之前运行。无论返回是提前发生的还是在正常执行结束时发生的,都会如此。

嵌套的 ensure 块

Ruby 允许使用带有自己的 ensure 子句的嵌套 begin 块。本示例显示了它们的执行顺序。

nested_ensure.rb
begin
  puts "Outer begin"
  
  begin
    puts "Inner begin"
    raise "Inner error" if rand < 0.5
  ensure
    puts "Inner ensure"
  end

  raise "Outer error" if rand < 0.5
rescue => e
  puts "Rescued: #{e}"
ensure
  puts "Outer ensure"
end

每个 ensure 块在其对应的 begin 块退出时运行。内部 ensure 在外部 ensure 之前运行,形成一个清理堆栈。

带线程的 ensure

线程中的 ensure 块在线程终止时执行,无论是正常终止还是由于异常终止。本示例演示了线程清理。

thread_ensure.rb
thread = Thread.new do
  begin
    puts "Thread working"
    sleep 1
    raise "Thread error" if rand < 0.5
  ensure
    puts "Thread cleanup"
  end
end

thread.join
puts "Main program continues"

无论线程成功完成还是引发异常,线程的 ensure 块都会运行。这对于线程本地资源的清理至关重要。

在方法定义中使用 ensure

方法可以使用 ensure 而无需显式的 begin 块。本示例显示了方法级 ensure 的简写语法。

method_ensure.rb
def process_data
  puts "Processing data"
  raise "Processing error" if rand < 0.4
rescue => e
  puts "Error: #{e}"
ensure
  puts "Cleanup resources"
end

process_data

整个方法体充当一个隐式的 begin 块。ensure 子句仍然保证执行,无论方法如何退出。

来源

Ruby 异常处理文档

本教程通过实际示例涵盖了 Ruby 的 ensure 关键字,展示了资源清理、线程安全和方法级保证。

作者

我的名字是 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出 所有 Ruby 教程