Rubyにおける変数とその挙動について
変数とは何か?
一般的にプログラミングを学ぶ際、変数は「値を格納する入れ物」として説明されることが多いです。しかし、この表現は初学者にとって分かりやすくするための単純化されたもので、Rubyのようなプログラミング言語の変数の実態とは少し違います。
実際には、変数は単なる入れ物ではなく、値の格納場所を指し示す「参照」や「ポインタ」として機能します。つまり、変数には値自体が直接格納されるのではなく、値が格納されているメモリ位置への参照が格納されるのです。
参照の理解とその挙動
まずはRubyの=
演算子がどのように動作するかを解説します。
参照とは何か?
まず基本から理解しましょう。Rubyにおける変数は、データそのものではなく、データが格納されているメモリの場所を指す「参照」を保持します。つまり、変数には実際のデータへのポインタが含まれており、そのポインタを通じてデータにアクセスすることができます。
=
演算子の役割
Rubyで =
演算子を使用するとき、実際に行われるのは値のコピーではなく、参照(またはポインタ)のコピーです。この挙動を明確に理解するために、以下の例を詳しく見ていきましょう。
data1 = [1, 2, 3]
data2 = data1
このコードでは、最初に配列 [1, 2, 3]
を data1
という変数に割り当てます。次に、data2 = data1
という行で data1
の持つ参照を data2
にコピーします。
object_id
メソッドの使用
この挙動を視覚的に確認するために、Rubyの object_id
メソッドを使用します。このメソッドは、オブジェクトの一意の識別子を返し、メモリ上のそのオブジェクトの位置を間接的に示します。識別子が同じであれば、それは同じオブジェクトを参照していることを意味します。上記のコードにおける object_id
の呼び出しを見てみましょう。
data1 = [1, 2, 3]
data2 = data1
puts data1.object_id # 60
puts data2.object_id # 60
ここで、data1
と data2
が同じ object_id
を出力しています。これは、両方の変数が同じ配列オブジェクト(メモリ上の同じ位置に存在する配列)を参照していることを示しています。
代入の影響と参照の動作
変数間で参照が共有されることの具体的な影響を見てみましょう。
data1 = [1, 2, 3]
data2 = data1
data1[0] = 10
p data1 # [10, 2, 3]
p data2 # [10, 2, 3]
この例では、data1
の最初の要素を 10
に変更すると、data2
が参照する配列も変更されていることが分かります。これは、両方の変数が同じ配列オブジェクトを共有しているためです。
しかし、次の例では挙動が異なります。
data1 = [1, 2, 3]
data2 = data1
data1 = [4, 5, 6]
p data1 # [4, 5, 6]
p data2 # [1, 2, 3]
p data1.object_id # 60
p data2.object_id # 80
この場合、data1
に新しい配列 [4, 5, 6]
を代入することで、data1
の参照が新しい配列に更新されますが、data2
の参照は変わらず最初の配列を指し続けるため、変更は data2
には影響しません。
即値として扱われる型の特例
Rubyではほとんどのオブジェクトが参照によって扱われますが、整数や浮動小数点数の一部の値、true
、false
、nil
、シンボルなどは即値として扱われます。即値とは、変数に直接値が格納される方式を指します。これは処理効率を向上させるための実装です。以下の例を見てみましょう。
num1 = 10
num2 = num1
puts num1.object_id # 21
puts num2.object_id # 21
ここで、num1
と num2
は同じ object_id
を持ちますが、これは処理効率上の理由から同じ値は同じオブジェクトとして管理されるからです。
同じobject_idをもっていますが、次のような場合、挙動が異なります。
num1 = 10
num2 = num1
num1 += 5
p num1 # 15
p num2 # 10
p num1.object_id # 31
p num2.object_id # 21
この例では、num1
に 5
を加えたことで 15
という新しい値を持つ新しいオブジェクトが作成され、num1
の参照が更新されます。
しかし、num2
は変更されずに 10
の値を持つ元のオブジェクトを指し続けます。これは整数型がイミュータブル(変更不可能)であるため、値が変更されると新しいオブジェクトが生成されるからです。
Discussion