Ruby中method_missing创建方法后立即执行的实现问题
嘿,这个问题我之前在动态方法定义的时候也踩过坑!你现在的代码逻辑是第一次调用未定义的add_xxx方法时,只完成了方法的定义,但没有执行方法里的业务逻辑,所以第一次调用相当于只是“注册”了方法,只有第二次调用已经存在的方法时才会生效。
咱们来改一下,核心就是在动态创建方法之后,立刻触发一次方法调用,把当前传入的参数传进去就行:
首先看修改后的完整代码(用更安全的define_method替代字符串拼接的instance_eval):
class Add def initialize() @result = "" end def output() puts @result end def method_missing(name, *args) if name.to_s.include? "add" # 用define_method动态生成方法,比字符串拼接更安全易读 define_method(name) do |*inner_args| @result << inner_args.to_s end # 关键:定义完立刻调用这个方法,传入当前的参数 send(name, *args) else # 必须调用父类的method_missing处理其他未定义方法,避免异常 super end end end a = Add.new a.add_1("1") # 现在会直接执行逻辑,同时创建方法 a.add_2("2") # 同上 a.add_2("2") # 直接调用已存在的方法 a.output # 输出122,和你期望的一致
关键点解释:
- 动态方法定义+即时调用:当
method_missing捕获到符合规则的方法名时,先用define_method把方法定义好,紧接着用send(name, *args)调用这个刚创建的方法,这样第一次调用就会执行@result << args.to_s的逻辑,而不是只定义方法。 - 使用
define_method替代字符串instance_eval:字符串拼接代码的方式存在安全风险(比如方法名里有特殊字符可能导致注入),而且可读性差。define_method是Ruby官方推荐的动态定义方法的方式,更安全也更易维护。 - 不要忘记
super:重写method_missing时,如果遇到不符合规则的未定义方法,一定要调用父类的method_missing,否则会导致Ruby无法抛出正确的NoMethodError,出现奇怪的行为。
如果你坚持要用原来的instance_eval方式,也可以在定义完代码后加一行send(name, *args),效果是一样的,但还是更推荐define_method的写法。
内容的提问来源于stack exchange,提问作者mre
相关产品推荐
相关产品推荐

