Ruby gsub然后冻结得到不同的object_id

问题描述 投票:0回答:1

我做了一个关于红宝石冻结的实验:

# example1
a = 'a'.freeze

puts "--Identical object_id--"
puts a.object_id
puts 'a'.freeze.object_id


# example 2
b = 'a'.gsub('a', 'b').freeze
another_b = 'a'.gsub('a', 'b').freeze

puts "--Got three different object_id--"
puts 'b'.freeze.object_id
puts b.object_id
puts another_b.object_id
b.frozen? #=> true

b和another_b是冻结字符串'b',为什么它们有不同的object_id?

ruby gsub freeze
1个回答
1
投票

Ruby(YARV)识别冻结的字符串文字并创建优化的指令序列:

$ ruby --dump=insns -e '"a".freeze'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,3)>==============================
0000 opt_str_freeze   "a"                                             (   1)[Li]
0002 leave

而不是非冻结的字符串:

$ ruby --dump=insns -e '"a"'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,3)>==============================
0000 putstring        "a"                                             (   1)[Li]
0002 leave

以这种方式优化的字符串将指代完全相同的对象,即它们具有相同的object_id。但它只适用于字符串文字,即"...".freeze。通过freeze调用send(:freeze)或在带插值的字符串上调用freeze或像变量一样非文字或调用方法的结果会导致普通的方法调用:

$ ruby --dump=insns -e '"a".to_s.freeze'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,15)>=============================
0000 putstring        "a"                                             (   1)[Li]
0002 opt_send_without_block <callinfo!mid:to_s, argc:0, ARGS_SIMPLE>, <callcache>
0005 opt_send_without_block <callinfo!mid:freeze, argc:0, ARGS_SIMPLE>, <callcache>
0008 leave

以这种方式冻结的字符串将是具有不同object_id的独特对象。

请注意,所有这些都是特定于实现的。您不应该依赖这些优化。

© www.soinside.com 2019 - 2024. All rights reserved.