写程序的时候,谁都不想遇到错误,但错误偏偏总爱找上门。比如你写了个读取文件的脚本,结果文件被误删了;或者用户输入了个根本不是数字的内容,你却要拿它做计算。这时候,ref="/tag/2028/" style="color:#E3A3CF;font-weight:bold;">Ruby 的异常处理机制就能派上用场了。
什么是异常?
在 Ruby 里,异常就是程序运行过程中出现的“意外状况”。比如除以零、访问不存在的方法、打开一个不存在的文件等等。如果不处理,程序就会直接崩溃,用户看到一堆红色的报错信息,体验极差。
Ruby 提供了 begin...rescue...end 这套结构来捕获并处理这些异常,让程序即使遇到问题也能“优雅地”继续运行,而不是直接退出。
基本语法长什么样?
最简单的异常处理结构如下:
begin
result = 10 / 0
rescue
puts "出错了:不能除以零"
end
这段代码运行时,虽然除以零会触发 ZeroDivisionError,但因为被 rescue 捕获了,程序不会中断,而是输出提示信息,然后继续往下走。
捕获特定类型的异常
并不是所有错误都该用同一种方式处理。Ruby 中不同问题会抛出不同类型的异常。你可以指定只捕获某类异常:
begin
File.open("missing.txt") { |f| f.read }
rescue Errno::ENOENT => e
puts "文件没找到:#{e.message}"
end
这里只捕获“文件不存在”的错误,其他问题(比如权限不足)还是会正常抛出,便于开发者定位问题。
多个 rescue 分支
有时候一段代码可能出多种问题,可以像这样分情况处理:
begin
num = Integer(user_input)
result = 100 / num
rescue ArgumentError
puts "输入的不是有效数字"
rescue ZeroDivisionError
puts "不能输入零哦"
end
这样用户输错内容或输入零时,都能得到对应的提示,程序依然稳稳运行。
确保某些代码一定执行:ensure
有些操作,比如关闭文件、断开数据库连接,不管中间有没有出错,都必须执行。Ruby 提供了 ensure 块:
file = nil
begin
file = File.open("data.txt")
content = file.read
result = process(content)
rescue IOError => e
puts "读取失败:#{e.message}"
ensure
file.close if file && !file.closed?
end
无论是否发生异常,ensure 里的代码都会执行,保证资源被正确释放。
主动抛出异常:raise
除了系统自动抛出,你也可以手动触发异常,比如验证用户输入时:
def withdraw(amount)
raise "金额不能为负" if amount < 0
# 执行取款逻辑
end
调用这个方法时如果传了负数,就会立即中断并报错。这样可以把问题暴露得更早,避免后续逻辑出更大乱子。
自定义异常类型
当你的项目复杂了,系统自带的异常类型可能不够用。可以自己定义:
class InsufficientFundsError < StandardError
end
# 使用
raise InsufficientFundsError, "余额不足,无法完成交易"
这样在处理金融类逻辑时,能更清晰地区分不同业务错误。
实际场景小例子
假设你写了个小工具,批量下载图片。网络不稳定时,个别链接可能超时。你不想因为一张图下失败就让整个程序停下来:
urls.each do |url|
begin
download_image(url)
puts "✅ #{url} 下载成功"
rescue SocketError, TimeoutError => e
puts "⚠️ 跳过 #{url}:#{e.message}"
end
end
这样即使有几个链接出问题,其他图片照样能下完,用户体验就好多了。
异常处理不是为了掩盖错误,而是为了让程序更有韧性。合理使用 Ruby 的这套机制,能让你写的代码更健壮、更贴近真实使用场景。