Ruby では、inspect() が object_id() が与えるものとは異なるある種のオブジェクト ID を出力するのはなぜですか?
概要
p 関数を使用してオブジェクトを出力すると、ID が与えられる場合がありますが、それは object_id() が与えるものとは異なります。数値が異なる理由は何ですか?
更新: 0x4684abc は 36971870 (0x234255E) とは異なります
>> a = Point.new
=> #<Point:0x4684abc>
>> a.object_id
=> 36971870
>> a.__id__
=> 36971870
>> "%X" % a.object_id
=> "234255E"
解決策
Inspection のデフォルト実装は to_s のデフォルト実装を呼び出します。これは、Object#to_s ドキュメントにあるように、オブジェクトの 16 進値を直接表示するだけです (メソッドの説明をクリックするとソースが表示されます)。
一方、object_id の実装の基礎となる C ソースのコメントは、オブジェクトのタイプに応じて、Ruby 値とオブジェクト ID に異なる「名前空間」があることを示しています (たとえば、Fixnum を除くすべての最下位ビットはゼロのようです)。これは Object#object_id ドキュメントで確認できます (クリックするとソースが表示されます)。
そこから、「オブジェクト ID 空間」 (object_id によって返される) ではオブジェクトの ID が右の 2 番目のビット (最初のビットは 0) から始まりますが、「値空間」 (inspect によって使用される) ではであることがわかります。右側の 3 番目のビットから始まります (最初の 2 ビットはゼロです)。したがって、値を「オブジェクト ID 空間」から「値空間」に変換するには、object_id を 1 ビット左にシフトし、inspect で表示されるのと同じ結果を得ることができます。
> '%x' % (36971870 << 1)
=> "4684abc"
> a = Foo.new
=> #<Foo:0x5cfe4>
> '%x' % (a.object_id << 1)
=> "5cfe4"
注: object_id に関する詳細は、当時 (2010 年) には正確でしたが、新しい Ruby バージョンで object_id がメモリ アドレスから分離された後は、正確ではなくなりました。答えは「object_id がオンデマンドで生成されるから」ということになります。コメントを参照してください。