为什么 `object_id` 的符号在 rails 控制台和 pry/irb 之间有所不同?

Why does `object_id` of symbols vary between rails console and pry/irb?

当我在调试 BasicObject#method_missing 时(我有一个 No Id Given 错误),我得出的结论是 rb_method_missing(int argc, const VALUE *argv, VALUE obj) 的第一个参数被映射到一个方法名(带有:symbol.object_id).

的帮助

我想检查一下,所以我在rails控制台输入:symbol.object_id (Rails 4.2/Ruby 2.2):

:symbol.object_id
# => 771548

然后我检查了 IRB (Ruby 2.2):

:symbol.object_id
# => 771548

一切看起来都很棒。我在 IRB 试过:

:michał_kulesza.object_id
# => 2531228

然后在 rails 控制台中:

:michał_kulesza.object_id
# => 7816668

为什么 :symbol 在两种情况下具有相同的 object_id:michał_kulesza 具有不同的?

为什么不呢? object_ids 只有四个属性:

  • object_id 是一个 Integer
  • 每个对象都有一个 object_id
  • 没有两个对象同时具有相同的object_id(但是,请注意,两个不同的对象可能在不同的次具有相同的object_id ,即 object_ids 可能会被重新使用)
  • 对象的 object_id 在其生命周期内不会改变

您的观察没有违反这四个属性中的任何一个,因此,它是完全有效的。

可能正在进行一些优化 and/or 缓存,因此某些 Symbol 始终具有相同的 object_id。无论如何,这纯粹是 YARV 的内部实现细节, 不是 Ruby.

的语义

例如,YARV优化了nilfalsetrueFixnums(Integers适合n-1位,其中n 是一个机器字的大小),flonums(Floats 适合 n-2 位,对于 n >= 64)和某些 Symbols,这个的一个副作用是这些对象总是具有相同的 object_id。但是,这并不能保证,例如,当引入 flonums 时,nilobject_id4 更改为 8

Why does :symbol have the same object_id in both cases while :michał_kulesza has a different one?

这是因为符号 :symbol 已经生成(由 gem):

$ irb

irb(main):001:0> Symbol.all_symbols.grep /sym/
#=> [:to_sym, :all_symbols, :symlink?, :symlink, :sym, :symbol, :@post_symbeg]
#                                                      ^^^^^^^

irb(main):002:0> :symbol.object_id
#=> 771548

如果你启动 IRB 而没有加载任何 gems,你会得到不同的结果:

$ ruby --disable-gems -S irb

irb(main):001:0> Symbol.all_symbols.grep /sym/
#=> [:to_sym, :all_symbols, :symlink?, :symlink, :@post_symbeg]

irb(main):002:0> :symbol.object_id
#=> 833308

:symbol 之前生成另一个符号会导致不同的对象 ID:

$ ruby --disable-gems -S irb

irb(main):001:0> :foo.object_id
#=> 833308

irb(main):002:0> :symbol.object_id
#=> 833628

Rails 生成许多符号,这就是为什么 :michał_kulesza 在 rails 控制台中具有更高的对象 ID。