RubyのFixnum
こんちはっす
Rubyの世界は全てオブジェクトである。ということを頭に叩き込んで勉強しております。しかし、最近奇妙なものにぶつかりました。
変数はオブジェクトを指すタグであって、変数は直接オブジェクトを保持しているわけではないという認識です。
下のコードで、hogeメソッドにはIntegerのオブジェクトを仮引数としてわたし、fugaメソッドにはArrayのオブジェクトを仮引数としてわたしました。hogeメソッドを実行すると実引数は変化なし、fugaメソッドを実行すると実引数が変更されました。hogeメソッド実行するとhogeメソッドにいれた実引数も変更されると思ったのですが、変更されませんでした。オブジェクトなのに?
def hoge(a, b) a += 10 b += 10 end x = 1 y = 2 p x.object_id #=> 3 p y.object_id #=> 5 hoge(x, y) p x.object_id #=> 3 p y.object_id #=> 5 #hogeメソッド実行結果 p x #=> 1 p y #=> 2 def fuga(ary) ary[0] += 10 ary[1] += 10 end array = [1, 2] p array.object_id #=> 70226961071960 p array[0].object_id #=> #=> 3 p array[1].object_id #=> #=> 5 fuga(array) p array.object_id #=> 70226961071960 p array[0].object_id #=> 23 p array[1].object_id #=> 25 #fugaメソッド実行結果 p array #=> [11, 12]
※object_idについて
object_idメソッドは、レシーバのオブジェクトIDを返します。オブジェクトIDは、オブジェクトごとに固有の整数値です。レシーバが同じオブジェクトなら必ず同じオブジェクトIDになり、違うオブジェクトなら別のオブジェクトIDが返ります。
object_id (Object) - Rubyリファレンス
アドレスではないみたいです。
Fixnumは特別扱い
では、Integerのオブジェクトが何で変更されなかったかについて
rubyではオブジェクトの実体を構造体で表現し、扱うときは常に ポインタ経由で扱う。第2章 オブジェクト
とのことですが、「小さな整数」は特別にポインタとして扱わず直接値として扱うという仕様があるらしいのです。てか、小さな整数ってなんですかていう話ですが、そいつの正体は「Fixnum」のことです。Fixnumの親クラスはIntegerです。Fixnumと同レベルにBignumというものがあります。Fixnumだった整数がある値を超えるとFixnumからBignumに変わります。仕様で整数の大きさでクラスが変わるみたいです。それでいつクラスが変わるのか?なんですが、調べている方がいました。感謝です。
4611686018427387903.class #=> Fixnum 4611686018427387904.class #=> Bignum -4611686018427387904.class #=> Fixnum -4611686018427387905.class #=> Bignum
つまり小さな整数を扱う場合は、直接整数を扱っているということになっているのである。なので、小さな整数Fixnumだと値を参照しているのではなく、値を直接保持しているということになっている。知らなかった。
これは、整数インスタンスが多すぎて、そんなに多くインスタンスつくるのはメモリ管理の手間なので、値が小さいときは特別扱いにするという仕様なんだと。
ちなみに、SymbolもFixnumと同じく、特別扱いになるらしい。