首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >修改Ruby无法修改方法

修改Ruby无法修改方法
EN

Stack Overflow用户
提问于 2016-05-13 20:09:50
回答 1查看 89关注 0票数 3

我是C的新手,试图通过Ruby源代码来学习更多知识。

当我从源代码编译Ruby时,它似乎没有意识到我对方法定义所做的任何更改。但是,如果我添加了一个新方法,比如string,指向一个修改过的方法,那么新方法就会像预期的那样工作。

代码语言:javascript
复制
# string.c

static VALUE
rb_str_empty(VALUE str)
{
    return Qtrue;
}

...

rb_define_method(rb_cString, "empty?", rb_str_empty, 0);
rb_define_method(rb_cString, "my_empty?", rb_str_empty, 0);

然后,在Ruby控制台中,我们看到新方法反映了新的定义,但是旧的方法仍然工作得好像方法没有被修改一样。

代码语言:javascript
复制
$ irb
> "sdf".my_empty?
true
> "sdf".empty?
false

Ruby是如何“保护”原始方法定义的?我怎样才能登记变更?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-13 22:17:51

当前版本的Ruby使用虚拟机。当您运行一些Ruby代码时,它首先被编译成字节码,然后这个字节码由虚拟机执行。VM包括诸如分配变量、创建类、定义方法和(针对这种情况的重要)调度方法等方面的指令。但是,对于一些常用的方法,还有一些特殊的优化字节码指令可以绕过正常的方法分派过程。就是这样的一种方法

您可以使用RubyVM::InstructionSequence.compile (和要查看的disasm )来查看字节码。首先是“正常”方法分派(使用不存在的方法foo):

代码语言:javascript
复制
> puts RubyVM::InstructionSequence.compile('"asdf".foo').disasm
== disasm: #<ISeq:<compiled>@<compiled>>================================
0000 trace            1                                               (   1)
0002 putstring        "asdf"
0004 opt_send_without_block <callinfo!mid:foo, argc:0, ARGS_SIMPLE>, <callcache>
0007 leave

opt_send_without_block是方法分派指令,试图调用foo (mid是“方法ID”)。

现在使用优化后的empty?字节码

代码语言:javascript
复制
> puts RubyVM::InstructionSequence.compile('"asdf".empty?').disasm
== disasm: #<ISeq:<compiled>@<compiled>>================================
0000 trace            1                                               (   1)
0002 putstring        "asdf"
0004 opt_empty_p      <callinfo!mid:empty?, argc:0, ARGS_SIMPLE>, <callcache>
0007 leave

opt_empty_pempty?方法的专用字节码指令。

如果将此指令的源代码与String#empty? (您更改的函数)进行比较,您可以看到在接收方为字符串的情况中,指令代码重复了函数的代码,完全绕过了该函数(在某些情况下,这些优化的指令直接调用实现函数,绕过方法分派代码,但使用相同的实现)。

该指令确实包括一个检查,以确保该方法在Ruby中没有被替换,但这显然不包括对C源代码的修改,如这里所示。

如果使用send,我认为您应该得到修改后的函数版本,因为这不能编译到优化的指令:

代码语言:javascript
复制
'asdf'.send :empty?

如果设置了编辑和重新编译Ruby,您还应该能够在文件insns.def中修改指令本身。此文件用于在生成过程中为指令创建代码。这不是C本身,但每个指令块的内容只是普通的C。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37218612

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档