在Ruby中,为什么inspect()会打印出与object_id()不同的对象id?

rhfm7lfc  于 2023-10-18  发布在  Ruby
关注(0)|答案(3)|浏览(99)

p函数用于打印出对象时,它可能会给予ID,并且它与object_id()所赋予的不同。不同数字的原因是什么?

更新:0x4684abc36971870不同,0x234255E

>> a = Point.new
=> #<Point:0x4684abc>

>> a.object_id
=> 36971870

>> a.__id__
=> 36971870

>> "%X" % a.object_id
=> "234255E"
hk8txs48

hk8txs481#

inspect的默认实现调用to_s的默认实现,它只是直接显示对象的十六进制值,如Object#to_s文档中所示(单击方法描述以显示源代码)。
同时,在object_id实现的C源代码中的注解显示,Ruby值和对象ID有不同的“命名空间”,这取决于对象的类型(例如,最低位似乎对于除Fixnum之外的所有都为零)。您可以在Object#object_id文档中看到这一点(单击以显示源代码)。
从这里我们可以看到,在“对象id空间”(由object_id返回)中,对象的id从右边的第二位开始(第一位为零),但在“值空间”(由inspect使用)中,它们从右边的第三位开始(前两位为零)。因此,要将值从“对象id空间”转换到“值空间”,我们可以将object_id向左移动一位,并获得与inspect相同的结果:

> '%x' % (36971870 << 1)
=> "4684abc"

> a = Foo.new
=> #<Foo:0x5cfe4>
> '%x' % (a.object_id << 1)
=> "5cfe4"

注意:关于object_id的细节在当时(2010年)是正确的,但在较新的Ruby版本将object_id与内存地址解耦之后,就不再正确了。现在的答案是沿着“因为object_id是按需生成的”。见评论。

dly7yett

dly7yett2#

0x234255E

=>36971870

它没有什么不同,它是内存地址的十六进制表示:-)

wvmv3b1j

wvmv3b1j3#

Ruby版本2.7将对象的object_id与内存地址本身解耦,因此不能将object_id转换为内存地址,反之亦然。实际上,对象的实际地址可以改变,而它的object_id保持不变。
也就是说,根据您的Ruby版本,ObjectSpace模块可能能够返回对象的内存地址。注意:这个库经常变化,所以你最好只在控制台中使用它。

# Using Ruby version 2.7.8 -- this code may not work in later versions!

require "objspace"
require "json"

object = Object.new
#=> #<Object:0x00007ff174981a08>

object_internals_json = ObjectSpace.dump(object)
#=> "{\"address\":\"0x7ff174981a08\", \"type\":\"OBJECT\", \"class\":\"0x7ff18d991250\", \"ivars\":0, \"memsize\":40, \"flags\":{\"wb_protected\":true}}\n"

JSON.parse(object_internals_json)["address"]
#=> "0x7ff174981a08"

相关问题