如何在Ruby中追踪字符串的创建?

3

这个单独问题的答案中,我说如果你执行以下操作:

name = "Rohit " "Sharma"

请注意,在创建一个包含内容为“Rohit Sharma”的新字符串对象时,您不需要使用包含“Rohit”和“Sharma”的两个String对象进行组合,而只需创建一个单独的字符串对象即可。

然而,这只是一本书告诉我这个道理,而不是手动验证它。

那么,您如何记录字符串的创建过程呢?

我尝试使用:

set_trace_func proc { |event, file, line, id, binding, classname|
  printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
}

string = "Insert content here"

但是只得到了这个。
c-return -:3  set_trace_func   Kernel
    line -:5

“Programming Ruby 1.9”(即Pickaxe)指出,修改“Class#new”对字符串无效,因为它们在构建时没有使用“new”。
2个回答

3

由于这个字符串连接是在解析时发生的,所以您无法记录它。

换句话说:无论您编写什么代码来记录此内容,连接都会在您的代码运行之前很久就已经发生了。

换句话说:您相信只有一个字符串对象是以相同的方式创建的,就像您相信42只创建一个值为42Fixnum对象,而不是创建42个值为1Fixnum对象。这是因为ISO Ruby语言规范如此规定,每个现有的Ruby实现源代码都是如此,每本书也都是如此。


1
我同意连接发生在解析时,但是连接后的字符串对象的创建不是在运行时发生吗? - Andrew Grimm
2
@Andrew Grimm:很可能。但请注意,对象创建不是您可以跟踪的8个事件之一。您只能跟踪调用Ruby方法、从Ruby方法返回、调用本地操作(在MRI、YARV中为C函数,在Rubinius中为C++方法等)、从本地操作返回、模块定义的开始、模块定义的结束、引发异常和执行行。 - Jörg W Mittag

0

这并不追踪字符串的创建,但以下内容表明在创建任何字符串对象之前发生了连接:

以下内容(我在Pickaxe的“幕后:Ruby VM”一节中读到过)在YARV中有效 - 我认为它在其他任何Ruby实现中都不会有效:

irb(main):003:0> uncompiled_code = 'name = "Rohit " "Sharma"'
=> "name = \"Rohit \" \"Sharma\""
irb(main):004:0> code = RubyVM::InstructionSequence.compile(uncompiled_code)
=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
irb(main):005:0> puts code.disassemble
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1] s1)
[ 2] name
0000 trace            1                                               (   1)
0002 putstring        "Rohit Sharma"
0004 dup
0005 setlocal         name
0007 leave
=> nil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接