我正在研究 Ruby 的 .object_id
并注意到,在 irb 的几个连续 session 中,我得到了这些相同的结果:
false.object_id // 0
true.object_id // 2
nil.object_id // 4
100.object_id // 201
事实上,每个整数的 object_id 似乎都是 ((value * 2) + 1)。
另一方面,给定字符串的 object_id 在退出并重新运行 irb 后不再相同。
这给我提出了几个问题:
- 是否有确定某些
object_id
的已知方案?其他人基本上是随机的吗? - true、false 和 nil 的 ID 不是连续的。有没有办法询问给定的 id 代表什么对象? (我很好奇其他个位数和 ID 与什么有关。)
- 你能(不是你应该)编写混淆的 Ruby,在其中使用已知的对象 ID 来引用对象而不命名它们,例如“id 201 的对象 + id 19 的对象”表示“100 + 9”吗?<
更新
根据 Andrew Grimm 的建议,我尝试发现其他“低 ID”对象,但发现:
- 此序列中似乎没有更多的偶数对象 - ID 6、8、10 等不指向任何东西。
- 正如我之前的实验所暗示的,所有奇数编号的 id 都属于数字。具体来说,id 1指向数字0,3指向1,5指向2,依此类推。
最佳答案
在 MRI 中 object_id
一个对象与 VALUE
相同表示 C 级别上的对象。对于大多数类型的对象,这 VALUE
是指向内存中存储实际对象数据的位置的指针。显然,这在多次运行期间会有所不同,因为它仅取决于系统决定分配内存的位置,而不取决于对象本身的任何属性。
但是出于性能原因true
, false
, nil
和 Fixnum
s是经过特殊处理的。对于这些对象,内存中实际上没有包含对象数据的结构。对象的所有数据都编码在 VALUE
中本身。正如您已经计算出 false
的值一样, true
, nil
和任何 Fixnum
i
, 是 0
, 2
, 4
和 i*2+1
分别。
之所以可行,是因为在运行 MRI 的任何系统上,0
, 2
, 4
和 i*2+1
永远不会是堆上对象的有效地址,因此与指向对象数据的指针没有重叠。
关于ruby - object_id 分配如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3430280/