alias 可以用来别名一个方法,生成其副本留以他用。在我们需要给一个方法增添一些内容,又不想重写一遍不需要改动的部分时,我们就可以用 alias。但是这个机制往往伴随着一个潜在的问题,那就是 alias 的老对头——无限循环。
来看一个简单的例子:
class A def fn p "instance method `fn'" end def foo alias fn_old fn def fn fn_old end fn end end a = A.new a.foo a.foo # Stack level too deep.
在第二次调用 foo 时发生了栈层次过深的异常。其原理是:在 A#foo 第一次调用、第一次 alias fn_old fn 时,由于 foo 内部的局部方法 fn 还没有定义,所以 alias 拷贝的是实例方法 A#fn 的一份副本;在 A#foo 第二次调用后,由于先前定义的局部方法 fn 已经存在于 A 的实例上下文中,所以第二次 alias 后 fn_old 就拷贝之前定义的局部方法 fn 的一份副本;而这个局部方法 fn 的副本又会去调用 fn_old—一个已经变成了这个局部方法本身副本的别名,于是 fn 调用 fn 自己,产生了没有出口的递归,导致最终抛出 `SystemStackError: Stack level too deep’ 的异常。
总结:两次对同一个方法 alias 同一个别名就会出现这样的情况。脚本编写者在使用 alias 时应尽量使别名不与自己或他人所写脚本的相同方法的别名碰撞,如添加上标识着脚本编写者的前缀: szsu_fn_old。在脚本有可能被重新执行时,使用 Module.method_defined? 等方法可判断出副本方法是否已定义,只有当方法副本没有定义时我们才定义,这样也可以有效地避免方法副本重定义。
8 Comments
这个是什么语言?
这是 Ruby。居然在这里看到你,稀客啊稀客。
国内访问wordpress大鸭梨,所以就过来吐吐槽 ^_^
codepad.org 和 fayaa.com不错,前者可以用于保存代码,后者可以生成代码高亮的Html代码,我的代码高亮插件就是这样解决的。
可能也只是部分线路有鸭梨?6R 上有人说通行无阻。
或许吧,有些时候访问还是比较快的,不过大多数情况大鸭梨。
现在我看你这个博客就像没有主题一样。
试了一下 codepad.org,果然好用,感谢分享!我没有设置主题是为了简洁,有一种返璞归真的美。另外似乎你博客里我的评论还未通过审核?
(囧,为啥找不到登录)无限循环常用的监控方法也就是defined?,但是经常诡异掉……
好吧……RSS在哪儿……
II 你也用 WordPress o.o
Meta 下面有 login 选项,RSS 么……全局的在 https://szsu.wordpress.com/feed/
用 defined? 等监控有一个问题,就是可能使用到比预期更老的方法别名,比如两次 alias 后,该方法已经被新增了两次内容,但第三次 alias 与第一次 alias 同名,于是变成了在第一次的基础上新增内容,覆盖了第二次新增的内容……