如何在Ruby类中捕获所有异常?附示例代码
Ruby类全局异常捕获的正确实现方式
嘿,我来帮你搞定这个Ruby全局异常捕获的需求~你之前写的代码其实有个小问题:rescue不能直接放在类定义的顶层,它必须包裹在begin...end块、方法内部,或者作为方法的修饰符来使用。下面给你两种靠谱的实现方案,满足你让子类方法自动捕获异常的需求:
方案一:用Mixin模块实现(推荐,更灵活)
这种方式用Ruby的模块混入特性,能给任意类添加异常捕获能力,不受单继承限制:
module ExceptionHandler def self.included(base) base.extend(ClassMethods) base.class_eval do @wrapped_methods = Set.new end end module ClassMethods # 钩子方法:当类新增实例方法时自动触发 def method_added(name) # 避免重复包装方法,跳过safe_wrap本身 return if @wrapped_methods.include?(name) || name == :safe_wrap @wrapped_methods.add(name) original_method = instance_method(name) # 重新定义方法,用异常捕获逻辑包装原方法 define_method(name) do |*args, &block| safe_wrap do original_method.bind(self).call(*args, &block) end end end end # 通用异常捕获逻辑 def safe_wrap yield rescue => e puts "Error!!! 异常信息:#{e.message}" end end # 使用示例 class ServiceA include ExceptionHandler def say_hello # 模拟抛出异常 raise "数据库连接失败" end end ServiceA.new.say_hello # => Error!!! 异常信息:数据库连接失败
方案说明
- 模块通过
included钩子给目标类添加类方法,method_added会在类新增实例方法时自动触发,把原方法包装进异常捕获逻辑里 - 用
Set记录已包装的方法,避免重复包装导致死循环 - 你可以根据需求修改
safe_wrap里的捕获逻辑,比如记录日志、返回默认值等
方案二:用父类继承实现
如果你的服务类本来就有继承关系,也可以用父类统一实现异常捕获:
class BaseService def self.method_added(name) return if @wrapped_methods&.include?(name) || name == :handle_exception @wrapped_methods ||= Set.new @wrapped_methods.add(name) original_method = instance_method(name) define_method(name) do |*args, &block| handle_exception do original_method.bind(self).call(*args, &block) end end end def handle_exception yield rescue => e puts "Error!!!" end end # 使用示例 class ServiceA < BaseService def say_hello # 模拟异常 error_code_here # 这里会抛出NameError异常 end end ServiceA.new.say_hello # => Error!!!
方案说明
- 父类
BaseService的method_added钩子会自动包装所有子类的实例方法 - 子类只需要继承
BaseService,不需要额外写任何捕获代码,方法抛出异常时会自动触发父类的handle_exception逻辑
内容的提问来源于stack exchange,提问作者Dean
相关产品推荐
相关产品推荐

