ZetCode

Ruby raise 方法

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

本教程解释了如何在 Ruby 程序中使用 raise 方法进行异常处理。raise 方法会触发 Ruby 程序中的异常。

raise 方法会创建并抛出异常。它会停止正常的程序流程,并将控制权转移到异常处理器。异常可以是内置类或自定义类。

妥善的异常处理可以使程序更健壮、更易于维护。raise 方法是 Ruby 中发出错误信号的关键。多种形式允许灵活地创建异常。

基本 raise 示例

这个简单的示例演示了 raise 的最基本形式。它会创建一个带有自定义消息的 RuntimeError。

basic_raise.rb
def divide(a, b)
  raise "Division by zero" if b == 0
  a / b
end

begin
  result = divide(10, 0)
  puts result
rescue => e
  puts "Error: #{e.message}"
end

当 b 为零时,raise 方法会停止执行。rescue 块会捕获异常并打印错误消息。这可以防止程序崩溃。

抛出特定的异常类

Ruby 允许为不同的错误情况抛出特定的异常类。这有助于进行精确的错误处理。

specific_exception.rb
def process_file(filename)
  raise ArgumentError, "Filename required" if filename.nil?
  raise Errno::ENOENT, "File not found" unless File.exist?(filename)
  
  File.read(filename)
end

begin
  process_file(nil)
rescue ArgumentError => e
  puts "Argument error: #{e}"
rescue Errno::ENOENT => e
  puts "File error: #{e}"
end

不同的异常类有助于区分错误类型。rescue 块可以适当地处理每种情况。这使得错误恢复更加具体。

重新抛出异常

有时您需要捕获一个异常,执行一些操作,然后重新抛出它。这可以保留原始异常,同时添加处理。

reraise.rb
def risky_operation
  raise "Original error"
end

begin
  risky_operation
rescue => e
  puts "Logging error: #{e.message}"
  raise # Re-raises the same exception
end

在 rescue 块中使用空的 raise 会重新抛出捕获到的异常。这种模式在传播错误之前进行日志记录或清理时很有用。

使用自定义异常类抛出异常

对于复杂的应用程序,自定义异常类可以提供更好的组织。它们可以携带额外的错误信息。

custom_exception.rb
class ValidationError < StandardError
  attr_reader :field
  
  def initialize(field, message)
    @field = field
    super(message)
  end
end

def validate_user(name)
  raise ValidationError.new(:name, "Name too short") if name.length < 3
  puts "Name validated"
end

begin
  validate_user("Al")
rescue ValidationError => e
  puts "Validation failed on #{e.field}: #{e.message}"
end

自定义异常可以存储有关错误的额外上下文。rescue 块可以访问自定义属性和标准消息。这使得错误处理更加丰富。

条件性抛出异常

raise 方法可以与条件一起使用,以选择性地触发异常。这使得错误检查更加简洁。

conditional_raise.rb
def calculate_discount(price, discount)
  raise ArgumentError, "Price must be positive" unless price > 0
  raise ArgumentError, "Discount must be 0-100%" unless (0..100).cover?(discount)
  
  price * (100 - discount) / 100.0
end

begin
  puts calculate_discount(100, 110)
rescue ArgumentError => e
  puts "Invalid input: #{e.message}"
end

带有 raise 的守卫子句可以简洁地验证输入。每个条件都有一个特定的错误消息。这可以快速失败并提供清晰的反馈。

抛出异常并保留回溯信息

有时您想在保留原始回溯信息的同时抛出一个新异常。这可以保持完整的错误上下文。

backtrace_raise.rb
def inner_method
  raise "Original error"
end

def outer_method
  inner_method
rescue => e
  raise "Wrapper error", cause: e
end

begin
  outer_method
rescue => e
  puts "Caught: #{e.message}"
  puts "Original cause: #{e.cause.message}"
  puts "Backtrace:\n#{e.backtrace.join("\n")}"
end

cause 选项将新异常与原始异常关联起来。回溯信息会显示两个错误点。这对于包装低级错误很有用。

使用 raise 确保清理

即使 raise 被触发,ensure 子句也能确保清理代码的执行。这可以防止资源泄漏。

ensure_cleanup.rb
def process_data
  file = File.open("data.txt", "w")
  
  begin
    # Simulate error during processing
    raise "Processing failed" if rand < 0.5
    
    file.puts "Success data"
  ensure
    file.close
    puts "File closed successfully"
  end
end

begin
  process_data
rescue => e
  puts "Operation failed: #{e.message}"
end

无论处理成功还是失败,ensure 块都会执行。文件总是会被正确关闭。这种模式对于资源管理至关重要。

来源

Ruby raise 方法文档

本教程涵盖了 Ruby 的 raise 方法,并通过示例展示了基本用法、自定义异常、错误传播和资源清理模式。

作者

我叫 Jan Bodnar,是一名热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Ruby 教程