ruby object.to_s之后如何找到之前的object

今天同事问了我一个问题,已知

1
2
a = User.first.to_s
"#<User:0x007fe9a579ba30>"

如何通过a找到User.first这个实例对象

首先查看了一下文档,找到了object.to_s方法,object.to_s方法是取到object的class_name以及object_id,但是它显示出的十六进制,跟直接通过

1
2
b = User.first.object_id
70320739687060

取出来的object_id不同,但是object.to_s取出object_id的时候对它是如何处理的呢?然后我搜到了一篇文章,里面有讲

C 中的注释源底层的实现 object_id 显示, 有不同的 Ruby值和对象id , 具体取决于对象的类型( 例如 最低位全部Fixnums除外) 似乎为零.

然后查看Object#object_id docs

最后得出结果

1
2
3
4
5
6
a = User.first
"#<User:0x007fe9a5673b58>"
a.object_id
70320739556780
'0x007fe9a5673b58'.hex >> 1
70320739556780

取出to_s生成的16进制object_id,把它转换为十进制,并右移一位。

找到了正确可用的object_id就可以通过

1
2
3
user = ObjectSpace._id2ref(70320739556780)
user == a
true

取到需要的实例对象。