先に結論
- rubyの代入はオブジェクトの参照値(ポインタのようなもの)が代入先に格納される
- もし、格納元が参照値の場合、同一の参照値が代入先に格納される(参照の参照にはならない)
- イメージとしては、C++のポインタの値の代入に近い
文字列"aaa"
を変数a
に代入する場合
a = "aaa"
上記の場合、以下の処理が実行される
Stringオブジェクト"aaa"
が生成される
- 変数
a
にStringオブジェクト"aaa"
の参照値が格納される
その変数a
を別の変数b
に代入するばあい
a = "aaa"
b = a
上記の場合、
- 変数
a
に格納されている Stringオブジェクト"aaa"
の参照値が、変数 b
に 格納される
同じオブジェクトが参照されていることが object_id
を比較すると分かる
a = "aaa"
b = a
a.object_id == b.object_id
変数b
に破壊的メソッドsub!
を実行した場合
a = "aaa"
b = a
b.sub!(/a/, 'b')
この場合、変数 a
も b
も同じオブジェクトを参照しているため、変数 a
の表示も変わる
a = "aaa"
b = a
b.sub!(/a/, 'b')
p b
p a
変数b
に別の文字列 "bbb"
を代入する場合
a = "aaa"
b = a
b = "bbb"
このばあい、変数b
には新たに生成されたStringオブジェクト"bbb"
の参照値が格納され、変数a
とは参照先が別になる
変数b
と変数a
の参照先が異なることが object_id
を比較すると分かる
a = "aaa"
b = a
b = "bbb"
a.object_id != b.object_id
ぎゃくに変数a
に別の文字列 "bbb"
を代入する場合
a = "aaa"
b = a
a = "bbb"
このばあい、変数a
にはStringオブジェクト"bbb"
の参照値が格納される
しかし、変数b
はStringオブジェクト"aaa"の参照値が格納されたままのため、文字列 "aaa"
が表示される
a = "aaa"
b = a
a = "bbb"
p b
a.object_id != b.object_id
上記のことから rubyの変数には参照ではなく、参照値が格納されていることが分かる
なんで?
もし、a="aaa"
が C++などで言う「参照」であるならば
b=a; b="bbb"
としたときに Stringオブジェクト"aaa"
の内容が "bbb"
に変わるはず
#include <iostream>
int main(void){
int x = 100;
int& xr = x;
xr = 200;
std::cout << "x=" << x << "\n";
return 0;
}
どちらかというと、C++でいうポインタの値の代入のイメージに近い
しかし、rubyではポインタは無いためJavaに倣って「参照値の代入」という言葉を選んだ
C++でのポインタの値の代入
#include <iostream>
int main(void){
int a = 100;
int* ap = &a;
std::cout << "ap=" << ap << "\n";
int* bp = ap;
std::cout << "bp=" << bp << "\n";
int b = 999;
bp = &b;
std::cout << "bp=" << bp << "\n";
std::cout << "a=" << a << "\n";
return 0;
}