Ruby 重写方法的疑问

yxmmrwx · 2025年01月08日 · 最后由 pamela02 回复于 2025年01月18日 · 321 次阅读

重写方法时,如果没有 alias_method :old_method,:method,那么内存中是否还存在着之前方法的实现?还是说被覆盖了?

非常感谢

答案:

  • 没有复制。

alias 做的事情:将方法入口名,改为 新名字,更新方法环境变量(所在类)。新名字,最后引用原始的方法。

CRuby 源码 简化

void
rb_alias(VALUE klass, ID alias_name, ID original_name)
{

    // 1)查找原始方法 
    // .....
    orig_me = search_method(klass, original_name, &defined_class);

    // 2) 继承关键信息
    // .....
    // 如果原始方法是 super 方法(VM_METHOD_TYPE_ZSUPER),则将 klass 设置为其父类,并将 original_name 设置为原始方法的原始 ID,然后跳转到 again 标签重新查找原始方法。
    // 如果原始方法是别名方法(VM_METHOD_TYPE_ALIAS),则获取原始方法的可见性,并将 orig_me 设置为原始方法的原始方法条目。断言原始方法的类型不是别名方法,以避免无限循环。

    switch (orig_me->def->type) {
      case VM_METHOD_TYPE_ZSUPER:
        klass = RCLASS_SUPER(klass);
        original_name = orig_me->def->original_id;
        visi = METHOD_ENTRY_VISI(orig_me);
        goto again;
      case VM_METHOD_TYPE_ALIAS:
        visi = METHOD_ENTRY_VISI(orig_me);
        orig_me = orig_me->def->body.alias.original_me;
        VM_ASSERT(orig_me->def->type != VM_METHOD_TYPE_ALIAS);
        break;
      default: break;
    }

    // 处理特殊方法,边界
    // ...... 省略


    // 3)设置 方法 入口
    // 调用 method_entry_set 函数在 target_klass 中为 alias_name 设置别名方法条目
    // 并且设置关联属性
    rb_method_entry_t *alias_me;

    alias_me = method_entry_set(target_klass, alias_name, orig_me, visi, orig_me->owner);
    RB_OBJ_WRITE(alias_me, &alias_me->owner, target_klass);

    if (RB_TYPE_P(target_klass, T_MODULE)) {
        // defined_class should not be set
    }
    else {
        RB_OBJ_WRITE(alias_me, &alias_me->defined_class, orig_me->defined_class);
    }
}
Mark24 回复

好像你回答的是重写方法时创建别名的过程(或者结果),但是我需要了解的是重写方法时如果不创建别名,结果将是怎样的?会不会原方法被覆盖了?(内存中不再有原方法的实现代码),mizuhashi 的回答更接近答案,不知道我理解的有没有问题

需要 登录 后方可回复, 如果你还没有账号请 注册新账号