object_id赋值如何工作?

我正在玩Ruby的.object_id ,注意到在irb的几个连续会话中,我得到了相同的结果:

 false.object_id // 0 true.object_id // 2 nil.object_id // 4 100.object_id // 201 

实际上,每个整数的object_id似乎都是((value * 2)+ 1)。

另一方面,在退出和重新运行irb之后,给定的string的object_id是绝不相同的。

这给我提出了几个问题:

  1. 有没有一个已知的scheme来确定某个object_id ? 其他人基本上是随机的
  2. 真,假,零的ID不是连续的。 有没有办法来问什么对象是由给定的ID代表? (我很好奇其他的一位数字和id是绑在一起的)
  3. 你可以(不是你应该)写混淆的Ruby,在那里你使用已知的对象ID来引用对象而不命名它们,比如“ID为201的对象+ ID为19的对象”表示“100 + 9”?

更新

使用安德鲁·格林的build议,我试图发现其他“低ID”的对象,但发现:

  • 在这个序列中似乎没有更多的偶数对象 – id 6,8​​,10等没有指向任何东西。
  • 正如我之前的实验所暗示的,所有的奇数ID都属于数字。 具体而言,id 1指向数字0,3指向1,5指向2,依此类推。

在MRI中,对象的object_id与表示C级别上的对象的VALUE相同。 对于大多数types的对象,这个VALUE是一个指向存储实际对象数据的内存位置的指针。 很显然,在多次运行中,这将是不同的,因为它只取决于系统决定分配内存的位置,而不取决于对象本身的任何属性。

然而,由于性能的原因, truefalsenilFixnum是专门处理。 对于这些对象,实际上并不存在与内存中的对象数据结构。 所有对象的数据都是在VALUE编码的。 正如你已经知道falsetruenilFixnum i分别是Fixnumi*2+1

这样做的原因是,在任何运行MRI的系统上,0,2,4和i*2+1永远都不是堆中对象的有效地址,因此不会与指向对象数据的指针重叠。

分配整数(value * 2) + 1和非整数(x * 2)类似于大酒店的希尔伯特悖论 ,它描述了如何将无限多的客人分配给无限的酒店。

关于通过ID查找对象,有ObjectSpace._id2ref(object_id) 。 除非你的实现没有ObjectSpace。