gpt4 book ai didi

ruby - 在 ruby​​ 中使用字符串插值会发生什么?

转载 作者:数据小太阳 更新时间:2023-10-29 06:44:06 26 4
gpt4 key购买 nike

我认为 ruby​​ 只是调用方法 to_s 但我无法解释它是如何工作的:

class Fake
def to_s
self
end
end

"#{Fake.new}"

根据逻辑,由于无限递归,这应该将堆栈级别提升得太深。但它工作正常,似乎从对象调用#to_s。

=> "#<Fake:0x137029f8>"

但为什么呢?

已添加:

class Fake
def to_s
Fake2.new
end
end

class Fake2
def to_s
"Fake2#to_s"
end
end

此代码在两种情况下的工作方式不同:

puts "#{Fake.new}" => "#<Fake:0x137d5ac4>"

但是:

puts Fake.new.to_s => "Fake2#to_s"

我觉得不正常。有人可以建议在 ruby​​ 解释器中何时在内部发生吗?

最佳答案

精简版

Ruby 会调用 to_s,但它会检查 to_s 是否返回一个字符串。如果没有,ruby 会调用 to_s 的默认实现。递归调用 to_s 不是一个好主意(不能保证终止)——您可能会使 VM 崩溃,而 ruby​​ 代码不应该使整个 VM 崩溃。

您从 Fake.new.to_s 得到不同的输出,因为 irb 调用 inspect 向您显示结果,而 inspect 调用 to_s 第二次

长版

要回答“当 ruby​​ 执行 x 时会发生什么”,一个好的起点是查看为 VM 生成了哪些指令(这都是 MRI 特定的)。对于您的示例:

puts RubyVM::InstructionSequence.compile('"#{Foo.new}"').disasm

输出

0000 trace            1                                               (   1)
0002 getinlinecache 9, <is:0>
0005 getconstant :Foo
0007 setinlinecache <is:0>
0009 opt_send_simple <callinfo!mid:new, argc:0, ARGS_SKIP>
0011 tostring
0012 concatstrings 1
0014 leave

缓存有些困惑,你总是会得到 traceleave 但简而言之就是这样说的。

  1. 获取常量 Foo
  2. 调用它的新方法
  3. 执行tostring指令
  4. 使用 tostring 指令的结果(堆栈中的最后一个值)执行 concatstrings 指令(如果您使用多个 #{} 序列执行此操作,您可以看到它构建了所有单独的字符串,然后在所有消耗时调用一次 concatstrings所有这些字符串)

此转储中的指令在 insns.def 中定义:这将这些指令映射到它们的实现。您可以看到 tostring 只是调用了 rb_obj_as_string

如果您通过 ruby​​ 代码库搜索 rb_obj_as_string(我发现 http://rxr.whitequark.org 对此很有用),您可以看到它被定义为 here作为

VALUE
rb_obj_as_string(VALUE obj)
{
VALUE str;

if (RB_TYPE_P(obj, T_STRING)) {
return obj;
}
str = rb_funcall(obj, id_to_s, 0);
if (!RB_TYPE_P(str, T_STRING))
return rb_any_to_s(obj);
if (OBJ_TAINTED(obj)) OBJ_TAINT(str);
return str;
}

简而言之,如果我们已经有一个字符串,则返回它。如果不是,则调用对象的 to_s 方法。然后,(这对您的问题至关重要),它会检查结果的类型。如果不是字符串,则返回 rb_any_to_s,这是实现默认 to_s

的函数

关于ruby - 在 ruby​​ 中使用字符串插值会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25488902/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com