Ruby中两种method_missing写法为何一种触发SystemStackError?
为什么这段Ruby代码会触发SystemStackError?
先看两段对比代码:
正常工作的实现
x = Object.new; x.define_singleton_method(:method_missing) { |*| x } x.foo.bar.baz == x # => true
触发栈溢出的实现
x = Object.new; def x.method_missing(*) x end x.foo # raises SystemStackError, stack level too deep
两者的核心差异在于**method_missing内部引用实例的方式不同**:
第一段用
define_singleton_method定义方法时,代码块是闭包,里面的x直接捕获了外部作用域的Object实例。每次调用method_missing都会直接返回这个实例,不会触发额外方法调用,链式调用能正常返回自身。第二段用
def x.method_missing(...)语法定义方法时,方法内部的x并不是外部变量,而是被Ruby解析为消息发送:即调用self.x(方法内部默认上下文self就是x实例)。当你调用x.foo时,因为x没有foo方法触发method_missing;而方法里的x会尝试调用x.x,但x同样没有x方法,又会再次触发method_missing——如此无限递归,最终撑爆调用栈,抛出SystemStackError。
如果要修正第二段代码,直接用self代替x即可,方法内部的self就是当前实例:
x = Object.new; def x.method_missing(*) self end x.foo.bar.baz == x # => true
内容的提问来源于stack exchange,提问作者Ulysse BN
相关产品推荐
相关产品推荐

